12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2ec561276SVivien Didelot /*
31d90016dSVivien Didelot  * Marvell 88E6xxx Switch Global 2 Registers support
4ec561276SVivien Didelot  *
5ec561276SVivien Didelot  * Copyright (c) 2008 Marvell Semiconductor
6ec561276SVivien Didelot  *
74333d619SVivien Didelot  * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
84333d619SVivien Didelot  *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
9ec561276SVivien Didelot  */
10ec561276SVivien Didelot 
11e289ef0dSVivien Didelot #include <linux/bitfield.h>
12282ccf6eSFlorian Westphal #include <linux/interrupt.h>
13dc30c35bSAndrew Lunn #include <linux/irqdomain.h>
144d5f2ba7SVivien Didelot 
154d5f2ba7SVivien Didelot #include "chip.h"
1682466921SVivien Didelot #include "global1.h" /* for MV88E6XXX_G1_STS_IRQ_DEVICE */
17ec561276SVivien Didelot #include "global2.h"
18ec561276SVivien Didelot 
19b000be95SBrandon Streiff int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
209fe850fbSVivien Didelot {
219069c13aSVivien Didelot 	return mv88e6xxx_read(chip, chip->info->global2_addr, reg, val);
229fe850fbSVivien Didelot }
239fe850fbSVivien Didelot 
24b000be95SBrandon Streiff int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
259fe850fbSVivien Didelot {
269069c13aSVivien Didelot 	return mv88e6xxx_write(chip, chip->info->global2_addr, reg, val);
279fe850fbSVivien Didelot }
289fe850fbSVivien Didelot 
29b000be95SBrandon Streiff int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update)
309fe850fbSVivien Didelot {
319069c13aSVivien Didelot 	return mv88e6xxx_update(chip, chip->info->global2_addr, reg, update);
329fe850fbSVivien Didelot }
339fe850fbSVivien Didelot 
34b000be95SBrandon Streiff int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
359fe850fbSVivien Didelot {
369069c13aSVivien Didelot 	return mv88e6xxx_wait(chip, chip->info->global2_addr, reg, mask);
379fe850fbSVivien Didelot }
389fe850fbSVivien Didelot 
39d6c5e6afSVivien Didelot /* Offset 0x00: Interrupt Source Register */
40d6c5e6afSVivien Didelot 
41d6c5e6afSVivien Didelot static int mv88e6xxx_g2_int_source(struct mv88e6xxx_chip *chip, u16 *src)
42d6c5e6afSVivien Didelot {
43d6c5e6afSVivien Didelot 	/* Read (and clear most of) the Interrupt Source bits */
44d6c5e6afSVivien Didelot 	return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_INT_SRC, src);
45d6c5e6afSVivien Didelot }
46d6c5e6afSVivien Didelot 
47d6c5e6afSVivien Didelot /* Offset 0x01: Interrupt Mask Register */
48d6c5e6afSVivien Didelot 
49d6c5e6afSVivien Didelot static int mv88e6xxx_g2_int_mask(struct mv88e6xxx_chip *chip, u16 mask)
50d6c5e6afSVivien Didelot {
51d6c5e6afSVivien Didelot 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_INT_MASK, mask);
52d6c5e6afSVivien Didelot }
53d6c5e6afSVivien Didelot 
546e55f698SAndrew Lunn /* Offset 0x02: Management Enable 2x */
5551c901a7SVivien Didelot 
5651c901a7SVivien Didelot static int mv88e6xxx_g2_mgmt_enable_2x(struct mv88e6xxx_chip *chip, u16 en2x)
5751c901a7SVivien Didelot {
5851c901a7SVivien Didelot 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_2X, en2x);
5951c901a7SVivien Didelot }
6051c901a7SVivien Didelot 
616e55f698SAndrew Lunn /* Offset 0x03: Management Enable 0x */
626e55f698SAndrew Lunn 
6351c901a7SVivien Didelot static int mv88e6xxx_g2_mgmt_enable_0x(struct mv88e6xxx_chip *chip, u16 en0x)
6451c901a7SVivien Didelot {
6551c901a7SVivien Didelot 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_0X, en0x);
6651c901a7SVivien Didelot }
6751c901a7SVivien Didelot 
6851c901a7SVivien Didelot /* Offset 0x05: Switch Management Register */
6951c901a7SVivien Didelot 
7051c901a7SVivien Didelot static int mv88e6xxx_g2_switch_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip,
7151c901a7SVivien Didelot 					     bool enable)
7251c901a7SVivien Didelot {
7351c901a7SVivien Didelot 	u16 val;
7451c901a7SVivien Didelot 	int err;
7551c901a7SVivien Didelot 
7651c901a7SVivien Didelot 	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SWITCH_MGMT, &val);
7751c901a7SVivien Didelot 	if (err)
7851c901a7SVivien Didelot 		return err;
7951c901a7SVivien Didelot 
8051c901a7SVivien Didelot 	if (enable)
8151c901a7SVivien Didelot 		val |= MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU;
8251c901a7SVivien Didelot 	else
8351c901a7SVivien Didelot 		val &= ~MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU;
8451c901a7SVivien Didelot 
8551c901a7SVivien Didelot 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MGMT, val);
8651c901a7SVivien Didelot }
8751c901a7SVivien Didelot 
8851c901a7SVivien Didelot int mv88e6185_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
8951c901a7SVivien Didelot {
9051c901a7SVivien Didelot 	int err;
9151c901a7SVivien Didelot 
9251c901a7SVivien Didelot 	/* Consider the frames with reserved multicast destination
9351c901a7SVivien Didelot 	 * addresses matching 01:80:c2:00:00:0x as MGMT.
9451c901a7SVivien Didelot 	 */
9551c901a7SVivien Didelot 	err = mv88e6xxx_g2_mgmt_enable_0x(chip, 0xffff);
9651c901a7SVivien Didelot 	if (err)
9751c901a7SVivien Didelot 		return err;
9851c901a7SVivien Didelot 
9951c901a7SVivien Didelot 	return mv88e6xxx_g2_switch_mgmt_rsvd2cpu(chip, true);
10051c901a7SVivien Didelot }
10151c901a7SVivien Didelot 
10251c901a7SVivien Didelot int mv88e6352_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
1036e55f698SAndrew Lunn {
1046e55f698SAndrew Lunn 	int err;
1056e55f698SAndrew Lunn 
1066e55f698SAndrew Lunn 	/* Consider the frames with reserved multicast destination
1076e55f698SAndrew Lunn 	 * addresses matching 01:80:c2:00:00:2x as MGMT.
1086e55f698SAndrew Lunn 	 */
10951c901a7SVivien Didelot 	err = mv88e6xxx_g2_mgmt_enable_2x(chip, 0xffff);
1106e55f698SAndrew Lunn 	if (err)
1116e55f698SAndrew Lunn 		return err;
1126e55f698SAndrew Lunn 
11351c901a7SVivien Didelot 	return mv88e6185_g2_mgmt_rsvd2cpu(chip);
1146e55f698SAndrew Lunn }
1156e55f698SAndrew Lunn 
116ec561276SVivien Didelot /* Offset 0x06: Device Mapping Table register */
117ec561276SVivien Didelot 
118c7f047b6SVivien Didelot int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target,
119c7f047b6SVivien Didelot 				      int port)
120ec561276SVivien Didelot {
121c7f047b6SVivien Didelot 	u16 val = (target << 8) | (port & 0x1f);
122c7f047b6SVivien Didelot 	/* Modern chips use 5 bits to define a device mapping port,
123c7f047b6SVivien Didelot 	 * but bit 4 is reserved on older chips, so it is safe to use.
124c7f047b6SVivien Didelot 	 */
125ec561276SVivien Didelot 
126067e474aSVivien Didelot 	return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_DEVICE_MAPPING, val);
127ec561276SVivien Didelot }
128ec561276SVivien Didelot 
129ec561276SVivien Didelot /* Offset 0x07: Trunk Mask Table register */
130ec561276SVivien Didelot 
131ec561276SVivien Didelot static int mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip *chip, int num,
13256dc7347SVivien Didelot 					 bool hash, u16 mask)
133ec561276SVivien Didelot {
13456dc7347SVivien Didelot 	u16 val = (num << 12) | (mask & mv88e6xxx_port_mask(chip));
135ec561276SVivien Didelot 
13656dc7347SVivien Didelot 	if (hash)
13756dc7347SVivien Didelot 		val |= MV88E6XXX_G2_TRUNK_MASK_HASH;
138ec561276SVivien Didelot 
13956dc7347SVivien Didelot 	return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_TRUNK_MASK, val);
140ec561276SVivien Didelot }
141ec561276SVivien Didelot 
142ec561276SVivien Didelot /* Offset 0x08: Trunk Mapping Table register */
143ec561276SVivien Didelot 
144ec561276SVivien Didelot static int mv88e6xxx_g2_trunk_mapping_write(struct mv88e6xxx_chip *chip, int id,
145ec561276SVivien Didelot 					    u16 map)
146ec561276SVivien Didelot {
147370b4ffbSVivien Didelot 	const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
148ec561276SVivien Didelot 	u16 val = (id << 11) | (map & port_mask);
149ec561276SVivien Didelot 
15056dc7347SVivien Didelot 	return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_TRUNK_MAPPING, val);
151ec561276SVivien Didelot }
152ec561276SVivien Didelot 
153b28f872dSVivien Didelot int mv88e6xxx_g2_trunk_clear(struct mv88e6xxx_chip *chip)
154ec561276SVivien Didelot {
155370b4ffbSVivien Didelot 	const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
156ec561276SVivien Didelot 	int i, err;
157ec561276SVivien Didelot 
158ec561276SVivien Didelot 	/* Clear all eight possible Trunk Mask vectors */
159ec561276SVivien Didelot 	for (i = 0; i < 8; ++i) {
160ec561276SVivien Didelot 		err = mv88e6xxx_g2_trunk_mask_write(chip, i, false, port_mask);
161ec561276SVivien Didelot 		if (err)
162ec561276SVivien Didelot 			return err;
163ec561276SVivien Didelot 	}
164ec561276SVivien Didelot 
165ec561276SVivien Didelot 	/* Clear all sixteen possible Trunk ID routing vectors */
166ec561276SVivien Didelot 	for (i = 0; i < 16; ++i) {
167ec561276SVivien Didelot 		err = mv88e6xxx_g2_trunk_mapping_write(chip, i, 0);
168ec561276SVivien Didelot 		if (err)
169ec561276SVivien Didelot 			return err;
170ec561276SVivien Didelot 	}
171ec561276SVivien Didelot 
172ec561276SVivien Didelot 	return 0;
173ec561276SVivien Didelot }
174ec561276SVivien Didelot 
175ec561276SVivien Didelot /* Offset 0x09: Ingress Rate Command register
176ec561276SVivien Didelot  * Offset 0x0A: Ingress Rate Data register
177ec561276SVivien Didelot  */
178ec561276SVivien Didelot 
179cd8da8bbSVivien Didelot static int mv88e6xxx_g2_irl_wait(struct mv88e6xxx_chip *chip)
180ec561276SVivien Didelot {
181cd8da8bbSVivien Didelot 	return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_IRL_CMD,
182cd8da8bbSVivien Didelot 				 MV88E6XXX_G2_IRL_CMD_BUSY);
183ec561276SVivien Didelot }
184ec561276SVivien Didelot 
185cd8da8bbSVivien Didelot static int mv88e6xxx_g2_irl_op(struct mv88e6xxx_chip *chip, u16 op, int port,
186cd8da8bbSVivien Didelot 			       int res, int reg)
187cd8da8bbSVivien Didelot {
188cd8da8bbSVivien Didelot 	int err;
189cd8da8bbSVivien Didelot 
190cd8da8bbSVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_IRL_CMD,
191cd8da8bbSVivien Didelot 				 MV88E6XXX_G2_IRL_CMD_BUSY | op | (port << 8) |
192cd8da8bbSVivien Didelot 				 (res << 5) | reg);
193cd8da8bbSVivien Didelot 	if (err)
194ec561276SVivien Didelot 		return err;
195cd8da8bbSVivien Didelot 
196cd8da8bbSVivien Didelot 	return mv88e6xxx_g2_irl_wait(chip);
197cd8da8bbSVivien Didelot }
198cd8da8bbSVivien Didelot 
199cd8da8bbSVivien Didelot int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
200cd8da8bbSVivien Didelot {
201cd8da8bbSVivien Didelot 	return mv88e6xxx_g2_irl_op(chip, MV88E6352_G2_IRL_CMD_OP_INIT_ALL, port,
202cd8da8bbSVivien Didelot 				   0, 0);
203cd8da8bbSVivien Didelot }
204cd8da8bbSVivien Didelot 
205cd8da8bbSVivien Didelot int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
206cd8da8bbSVivien Didelot {
207cd8da8bbSVivien Didelot 	return mv88e6xxx_g2_irl_op(chip, MV88E6390_G2_IRL_CMD_OP_INIT_ALL, port,
208cd8da8bbSVivien Didelot 				   0, 0);
209ec561276SVivien Didelot }
210ec561276SVivien Didelot 
21117a1594eSVivien Didelot /* Offset 0x0B: Cross-chip Port VLAN (Addr) Register
21217a1594eSVivien Didelot  * Offset 0x0C: Cross-chip Port VLAN Data Register
21317a1594eSVivien Didelot  */
21417a1594eSVivien Didelot 
21517a1594eSVivien Didelot static int mv88e6xxx_g2_pvt_op_wait(struct mv88e6xxx_chip *chip)
21617a1594eSVivien Didelot {
21767d1ea8eSVivien Didelot 	return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_PVT_ADDR,
21867d1ea8eSVivien Didelot 				 MV88E6XXX_G2_PVT_ADDR_BUSY);
21917a1594eSVivien Didelot }
22017a1594eSVivien Didelot 
22117a1594eSVivien Didelot static int mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip *chip, int src_dev,
22217a1594eSVivien Didelot 			       int src_port, u16 op)
22317a1594eSVivien Didelot {
22417a1594eSVivien Didelot 	int err;
22517a1594eSVivien Didelot 
22667d1ea8eSVivien Didelot 	/* 9-bit Cross-chip PVT pointer: with MV88E6XXX_G2_MISC_5_BIT_PORT
22767d1ea8eSVivien Didelot 	 * cleared, source device is 5-bit, source port is 4-bit.
22817a1594eSVivien Didelot 	 */
22967d1ea8eSVivien Didelot 	op |= MV88E6XXX_G2_PVT_ADDR_BUSY;
23017a1594eSVivien Didelot 	op |= (src_dev & 0x1f) << 4;
23117a1594eSVivien Didelot 	op |= (src_port & 0xf);
23217a1594eSVivien Didelot 
23367d1ea8eSVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_ADDR, op);
23417a1594eSVivien Didelot 	if (err)
23517a1594eSVivien Didelot 		return err;
23617a1594eSVivien Didelot 
23717a1594eSVivien Didelot 	return mv88e6xxx_g2_pvt_op_wait(chip);
23817a1594eSVivien Didelot }
23917a1594eSVivien Didelot 
24017a1594eSVivien Didelot int mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev,
24117a1594eSVivien Didelot 			   int src_port, u16 data)
24217a1594eSVivien Didelot {
24317a1594eSVivien Didelot 	int err;
24417a1594eSVivien Didelot 
24517a1594eSVivien Didelot 	err = mv88e6xxx_g2_pvt_op_wait(chip);
24617a1594eSVivien Didelot 	if (err)
24717a1594eSVivien Didelot 		return err;
24817a1594eSVivien Didelot 
24967d1ea8eSVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_DATA, data);
25017a1594eSVivien Didelot 	if (err)
25117a1594eSVivien Didelot 		return err;
25217a1594eSVivien Didelot 
25317a1594eSVivien Didelot 	return mv88e6xxx_g2_pvt_op(chip, src_dev, src_port,
25467d1ea8eSVivien Didelot 				   MV88E6XXX_G2_PVT_ADDR_OP_WRITE_PVLAN);
25517a1594eSVivien Didelot }
25617a1594eSVivien Didelot 
257ec561276SVivien Didelot /* Offset 0x0D: Switch MAC/WoL/WoF register */
258ec561276SVivien Didelot 
259ec561276SVivien Didelot static int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip,
260ec561276SVivien Didelot 					 unsigned int pointer, u8 data)
261ec561276SVivien Didelot {
262ec561276SVivien Didelot 	u16 val = (pointer << 8) | data;
263ec561276SVivien Didelot 
264ed44152fSVivien Didelot 	return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_SWITCH_MAC, val);
265ec561276SVivien Didelot }
266ec561276SVivien Didelot 
267ec561276SVivien Didelot int mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr)
268ec561276SVivien Didelot {
269ec561276SVivien Didelot 	int i, err;
270ec561276SVivien Didelot 
271ec561276SVivien Didelot 	for (i = 0; i < 6; i++) {
272ec561276SVivien Didelot 		err = mv88e6xxx_g2_switch_mac_write(chip, i, addr[i]);
273ec561276SVivien Didelot 		if (err)
274ec561276SVivien Didelot 			break;
275ec561276SVivien Didelot 	}
276ec561276SVivien Didelot 
277ec561276SVivien Didelot 	return err;
278ec561276SVivien Didelot }
279ec561276SVivien Didelot 
280ec561276SVivien Didelot /* Offset 0x0F: Priority Override Table */
281ec561276SVivien Didelot 
282ec561276SVivien Didelot static int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer,
283ec561276SVivien Didelot 				  u8 data)
284ec561276SVivien Didelot {
285ec561276SVivien Didelot 	u16 val = (pointer << 8) | (data & 0x7);
286ec561276SVivien Didelot 
2871d90016dSVivien Didelot 	return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_PRIO_OVERRIDE, val);
288ec561276SVivien Didelot }
289ec561276SVivien Didelot 
2909e907d73SVivien Didelot int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip)
291ec561276SVivien Didelot {
292ec561276SVivien Didelot 	int i, err;
293ec561276SVivien Didelot 
294ec561276SVivien Didelot 	/* Clear all sixteen possible Priority Override entries */
295ec561276SVivien Didelot 	for (i = 0; i < 16; i++) {
296ec561276SVivien Didelot 		err = mv88e6xxx_g2_pot_write(chip, i, 0);
297ec561276SVivien Didelot 		if (err)
298ec561276SVivien Didelot 			break;
299ec561276SVivien Didelot 	}
300ec561276SVivien Didelot 
301ec561276SVivien Didelot 	return err;
302ec561276SVivien Didelot }
303ec561276SVivien Didelot 
304ec561276SVivien Didelot /* Offset 0x14: EEPROM Command
30598fc3c6fSVivien Didelot  * Offset 0x15: EEPROM Data (for 16-bit data access)
30698fc3c6fSVivien Didelot  * Offset 0x15: EEPROM Addr (for 8-bit data access)
307ec561276SVivien Didelot  */
308ec561276SVivien Didelot 
309ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
310ec561276SVivien Didelot {
3117fc8c9d5SVivien Didelot 	return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_EEPROM_CMD,
3127fc8c9d5SVivien Didelot 				 MV88E6XXX_G2_EEPROM_CMD_BUSY |
3137fc8c9d5SVivien Didelot 				 MV88E6XXX_G2_EEPROM_CMD_RUNNING);
314ec561276SVivien Didelot }
315ec561276SVivien Didelot 
316ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
317ec561276SVivien Didelot {
318ec561276SVivien Didelot 	int err;
319ec561276SVivien Didelot 
3207fc8c9d5SVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_EEPROM_CMD,
3217fc8c9d5SVivien Didelot 				 MV88E6XXX_G2_EEPROM_CMD_BUSY | cmd);
322ec561276SVivien Didelot 	if (err)
323ec561276SVivien Didelot 		return err;
324ec561276SVivien Didelot 
325ec561276SVivien Didelot 	return mv88e6xxx_g2_eeprom_wait(chip);
326ec561276SVivien Didelot }
327ec561276SVivien Didelot 
32898fc3c6fSVivien Didelot static int mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip *chip,
32998fc3c6fSVivien Didelot 				     u16 addr, u8 *data)
33098fc3c6fSVivien Didelot {
3317fc8c9d5SVivien Didelot 	u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ;
33298fc3c6fSVivien Didelot 	int err;
33398fc3c6fSVivien Didelot 
33498fc3c6fSVivien Didelot 	err = mv88e6xxx_g2_eeprom_wait(chip);
33598fc3c6fSVivien Didelot 	if (err)
33698fc3c6fSVivien Didelot 		return err;
33798fc3c6fSVivien Didelot 
3387fc8c9d5SVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr);
33998fc3c6fSVivien Didelot 	if (err)
34098fc3c6fSVivien Didelot 		return err;
34198fc3c6fSVivien Didelot 
34298fc3c6fSVivien Didelot 	err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
34398fc3c6fSVivien Didelot 	if (err)
34498fc3c6fSVivien Didelot 		return err;
34598fc3c6fSVivien Didelot 
3467fc8c9d5SVivien Didelot 	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &cmd);
34798fc3c6fSVivien Didelot 	if (err)
34898fc3c6fSVivien Didelot 		return err;
34998fc3c6fSVivien Didelot 
35098fc3c6fSVivien Didelot 	*data = cmd & 0xff;
35198fc3c6fSVivien Didelot 
35298fc3c6fSVivien Didelot 	return 0;
35398fc3c6fSVivien Didelot }
35498fc3c6fSVivien Didelot 
35598fc3c6fSVivien Didelot static int mv88e6xxx_g2_eeprom_write8(struct mv88e6xxx_chip *chip,
35698fc3c6fSVivien Didelot 				      u16 addr, u8 data)
35798fc3c6fSVivien Didelot {
3587fc8c9d5SVivien Didelot 	u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE |
3597fc8c9d5SVivien Didelot 		MV88E6XXX_G2_EEPROM_CMD_WRITE_EN;
36098fc3c6fSVivien Didelot 	int err;
36198fc3c6fSVivien Didelot 
36298fc3c6fSVivien Didelot 	err = mv88e6xxx_g2_eeprom_wait(chip);
36398fc3c6fSVivien Didelot 	if (err)
36498fc3c6fSVivien Didelot 		return err;
36598fc3c6fSVivien Didelot 
3667fc8c9d5SVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr);
36798fc3c6fSVivien Didelot 	if (err)
36898fc3c6fSVivien Didelot 		return err;
36998fc3c6fSVivien Didelot 
37098fc3c6fSVivien Didelot 	return mv88e6xxx_g2_eeprom_cmd(chip, cmd | data);
37198fc3c6fSVivien Didelot }
37298fc3c6fSVivien Didelot 
373ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip,
374ec561276SVivien Didelot 				      u8 addr, u16 *data)
375ec561276SVivien Didelot {
3767fc8c9d5SVivien Didelot 	u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ | addr;
377ec561276SVivien Didelot 	int err;
378ec561276SVivien Didelot 
379ec561276SVivien Didelot 	err = mv88e6xxx_g2_eeprom_wait(chip);
380ec561276SVivien Didelot 	if (err)
381ec561276SVivien Didelot 		return err;
382ec561276SVivien Didelot 
383ec561276SVivien Didelot 	err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
384ec561276SVivien Didelot 	if (err)
385ec561276SVivien Didelot 		return err;
386ec561276SVivien Didelot 
3877fc8c9d5SVivien Didelot 	return mv88e6xxx_g2_read(chip, MV88E6352_G2_EEPROM_DATA, data);
388ec561276SVivien Didelot }
389ec561276SVivien Didelot 
390ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip *chip,
391ec561276SVivien Didelot 				       u8 addr, u16 data)
392ec561276SVivien Didelot {
3937fc8c9d5SVivien Didelot 	u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE | addr;
394ec561276SVivien Didelot 	int err;
395ec561276SVivien Didelot 
396ec561276SVivien Didelot 	err = mv88e6xxx_g2_eeprom_wait(chip);
397ec561276SVivien Didelot 	if (err)
398ec561276SVivien Didelot 		return err;
399ec561276SVivien Didelot 
4007fc8c9d5SVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6352_G2_EEPROM_DATA, data);
401ec561276SVivien Didelot 	if (err)
402ec561276SVivien Didelot 		return err;
403ec561276SVivien Didelot 
404ec561276SVivien Didelot 	return mv88e6xxx_g2_eeprom_cmd(chip, cmd);
405ec561276SVivien Didelot }
406ec561276SVivien Didelot 
40798fc3c6fSVivien Didelot int mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip *chip,
40898fc3c6fSVivien Didelot 			     struct ethtool_eeprom *eeprom, u8 *data)
40998fc3c6fSVivien Didelot {
41098fc3c6fSVivien Didelot 	unsigned int offset = eeprom->offset;
41198fc3c6fSVivien Didelot 	unsigned int len = eeprom->len;
41298fc3c6fSVivien Didelot 	int err;
41398fc3c6fSVivien Didelot 
41498fc3c6fSVivien Didelot 	eeprom->len = 0;
41598fc3c6fSVivien Didelot 
41698fc3c6fSVivien Didelot 	while (len) {
41798fc3c6fSVivien Didelot 		err = mv88e6xxx_g2_eeprom_read8(chip, offset, data);
41898fc3c6fSVivien Didelot 		if (err)
41998fc3c6fSVivien Didelot 			return err;
42098fc3c6fSVivien Didelot 
42198fc3c6fSVivien Didelot 		eeprom->len++;
42298fc3c6fSVivien Didelot 		offset++;
42398fc3c6fSVivien Didelot 		data++;
42498fc3c6fSVivien Didelot 		len--;
42598fc3c6fSVivien Didelot 	}
42698fc3c6fSVivien Didelot 
42798fc3c6fSVivien Didelot 	return 0;
42898fc3c6fSVivien Didelot }
42998fc3c6fSVivien Didelot 
43098fc3c6fSVivien Didelot int mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip *chip,
43198fc3c6fSVivien Didelot 			     struct ethtool_eeprom *eeprom, u8 *data)
43298fc3c6fSVivien Didelot {
43398fc3c6fSVivien Didelot 	unsigned int offset = eeprom->offset;
43498fc3c6fSVivien Didelot 	unsigned int len = eeprom->len;
43598fc3c6fSVivien Didelot 	int err;
43698fc3c6fSVivien Didelot 
43798fc3c6fSVivien Didelot 	eeprom->len = 0;
43898fc3c6fSVivien Didelot 
43998fc3c6fSVivien Didelot 	while (len) {
44098fc3c6fSVivien Didelot 		err = mv88e6xxx_g2_eeprom_write8(chip, offset, *data);
44198fc3c6fSVivien Didelot 		if (err)
44298fc3c6fSVivien Didelot 			return err;
44398fc3c6fSVivien Didelot 
44498fc3c6fSVivien Didelot 		eeprom->len++;
44598fc3c6fSVivien Didelot 		offset++;
44698fc3c6fSVivien Didelot 		data++;
44798fc3c6fSVivien Didelot 		len--;
44898fc3c6fSVivien Didelot 	}
44998fc3c6fSVivien Didelot 
45098fc3c6fSVivien Didelot 	return 0;
45198fc3c6fSVivien Didelot }
45298fc3c6fSVivien Didelot 
453ec561276SVivien Didelot int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
454ec561276SVivien Didelot 			      struct ethtool_eeprom *eeprom, u8 *data)
455ec561276SVivien Didelot {
456ec561276SVivien Didelot 	unsigned int offset = eeprom->offset;
457ec561276SVivien Didelot 	unsigned int len = eeprom->len;
458ec561276SVivien Didelot 	u16 val;
459ec561276SVivien Didelot 	int err;
460ec561276SVivien Didelot 
461ec561276SVivien Didelot 	eeprom->len = 0;
462ec561276SVivien Didelot 
463ec561276SVivien Didelot 	if (offset & 1) {
464ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
465ec561276SVivien Didelot 		if (err)
466ec561276SVivien Didelot 			return err;
467ec561276SVivien Didelot 
468ec561276SVivien Didelot 		*data++ = (val >> 8) & 0xff;
469ec561276SVivien Didelot 
470ec561276SVivien Didelot 		offset++;
471ec561276SVivien Didelot 		len--;
472ec561276SVivien Didelot 		eeprom->len++;
473ec561276SVivien Didelot 	}
474ec561276SVivien Didelot 
475ec561276SVivien Didelot 	while (len >= 2) {
476ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
477ec561276SVivien Didelot 		if (err)
478ec561276SVivien Didelot 			return err;
479ec561276SVivien Didelot 
480ec561276SVivien Didelot 		*data++ = val & 0xff;
481ec561276SVivien Didelot 		*data++ = (val >> 8) & 0xff;
482ec561276SVivien Didelot 
483ec561276SVivien Didelot 		offset += 2;
484ec561276SVivien Didelot 		len -= 2;
485ec561276SVivien Didelot 		eeprom->len += 2;
486ec561276SVivien Didelot 	}
487ec561276SVivien Didelot 
488ec561276SVivien Didelot 	if (len) {
489ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
490ec561276SVivien Didelot 		if (err)
491ec561276SVivien Didelot 			return err;
492ec561276SVivien Didelot 
493ec561276SVivien Didelot 		*data++ = val & 0xff;
494ec561276SVivien Didelot 
495ec561276SVivien Didelot 		offset++;
496ec561276SVivien Didelot 		len--;
497ec561276SVivien Didelot 		eeprom->len++;
498ec561276SVivien Didelot 	}
499ec561276SVivien Didelot 
500ec561276SVivien Didelot 	return 0;
501ec561276SVivien Didelot }
502ec561276SVivien Didelot 
503ec561276SVivien Didelot int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
504ec561276SVivien Didelot 			      struct ethtool_eeprom *eeprom, u8 *data)
505ec561276SVivien Didelot {
506ec561276SVivien Didelot 	unsigned int offset = eeprom->offset;
507ec561276SVivien Didelot 	unsigned int len = eeprom->len;
508ec561276SVivien Didelot 	u16 val;
509ec561276SVivien Didelot 	int err;
510ec561276SVivien Didelot 
511ec561276SVivien Didelot 	/* Ensure the RO WriteEn bit is set */
5127fc8c9d5SVivien Didelot 	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &val);
513ec561276SVivien Didelot 	if (err)
514ec561276SVivien Didelot 		return err;
515ec561276SVivien Didelot 
5167fc8c9d5SVivien Didelot 	if (!(val & MV88E6XXX_G2_EEPROM_CMD_WRITE_EN))
517ec561276SVivien Didelot 		return -EROFS;
518ec561276SVivien Didelot 
519ec561276SVivien Didelot 	eeprom->len = 0;
520ec561276SVivien Didelot 
521ec561276SVivien Didelot 	if (offset & 1) {
522ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
523ec561276SVivien Didelot 		if (err)
524ec561276SVivien Didelot 			return err;
525ec561276SVivien Didelot 
526ec561276SVivien Didelot 		val = (*data++ << 8) | (val & 0xff);
527ec561276SVivien Didelot 
528ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
529ec561276SVivien Didelot 		if (err)
530ec561276SVivien Didelot 			return err;
531ec561276SVivien Didelot 
532ec561276SVivien Didelot 		offset++;
533ec561276SVivien Didelot 		len--;
534ec561276SVivien Didelot 		eeprom->len++;
535ec561276SVivien Didelot 	}
536ec561276SVivien Didelot 
537ec561276SVivien Didelot 	while (len >= 2) {
538ec561276SVivien Didelot 		val = *data++;
539ec561276SVivien Didelot 		val |= *data++ << 8;
540ec561276SVivien Didelot 
541ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
542ec561276SVivien Didelot 		if (err)
543ec561276SVivien Didelot 			return err;
544ec561276SVivien Didelot 
545ec561276SVivien Didelot 		offset += 2;
546ec561276SVivien Didelot 		len -= 2;
547ec561276SVivien Didelot 		eeprom->len += 2;
548ec561276SVivien Didelot 	}
549ec561276SVivien Didelot 
550ec561276SVivien Didelot 	if (len) {
551ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
552ec561276SVivien Didelot 		if (err)
553ec561276SVivien Didelot 			return err;
554ec561276SVivien Didelot 
555ec561276SVivien Didelot 		val = (val & 0xff00) | *data++;
556ec561276SVivien Didelot 
557ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
558ec561276SVivien Didelot 		if (err)
559ec561276SVivien Didelot 			return err;
560ec561276SVivien Didelot 
561ec561276SVivien Didelot 		offset++;
562ec561276SVivien Didelot 		len--;
563ec561276SVivien Didelot 		eeprom->len++;
564ec561276SVivien Didelot 	}
565ec561276SVivien Didelot 
566ec561276SVivien Didelot 	return 0;
567ec561276SVivien Didelot }
568ec561276SVivien Didelot 
569ec561276SVivien Didelot /* Offset 0x18: SMI PHY Command Register
570ec561276SVivien Didelot  * Offset 0x19: SMI PHY Data Register
571ec561276SVivien Didelot  */
572ec561276SVivien Didelot 
573ec561276SVivien Didelot static int mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip *chip)
574ec561276SVivien Didelot {
575e289ef0dSVivien Didelot 	return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_SMI_PHY_CMD,
576e289ef0dSVivien Didelot 				 MV88E6XXX_G2_SMI_PHY_CMD_BUSY);
577ec561276SVivien Didelot }
578ec561276SVivien Didelot 
579ec561276SVivien Didelot static int mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
580ec561276SVivien Didelot {
581ec561276SVivien Didelot 	int err;
582ec561276SVivien Didelot 
583e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_CMD,
584e289ef0dSVivien Didelot 				 MV88E6XXX_G2_SMI_PHY_CMD_BUSY | cmd);
585ec561276SVivien Didelot 	if (err)
586ec561276SVivien Didelot 		return err;
587ec561276SVivien Didelot 
588ec561276SVivien Didelot 	return mv88e6xxx_g2_smi_phy_wait(chip);
589ec561276SVivien Didelot }
590ec561276SVivien Didelot 
591e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_access(struct mv88e6xxx_chip *chip,
592e289ef0dSVivien Didelot 				       bool external, bool c45, u16 op, int dev,
593e289ef0dSVivien Didelot 				       int reg)
594ec561276SVivien Didelot {
595e289ef0dSVivien Didelot 	u16 cmd = op;
596ec561276SVivien Didelot 
597cf3e80dfSAndrew Lunn 	if (external)
598e289ef0dSVivien Didelot 		cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_EXTERNAL;
599e289ef0dSVivien Didelot 	else
600e289ef0dSVivien Didelot 		cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_INTERNAL; /* empty mask */
601cf3e80dfSAndrew Lunn 
602e289ef0dSVivien Didelot 	if (c45)
603e289ef0dSVivien Didelot 		cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_45; /* empty mask */
604e289ef0dSVivien Didelot 	else
605e289ef0dSVivien Didelot 		cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_22;
606cf3e80dfSAndrew Lunn 
607e289ef0dSVivien Didelot 	dev <<= __bf_shf(MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK);
608e289ef0dSVivien Didelot 	cmd |= dev & MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK;
609e289ef0dSVivien Didelot 	cmd |= reg & MV88E6XXX_G2_SMI_PHY_CMD_REG_ADDR_MASK;
610cf3e80dfSAndrew Lunn 
611cf3e80dfSAndrew Lunn 	return mv88e6xxx_g2_smi_phy_cmd(chip, cmd);
612cf3e80dfSAndrew Lunn }
613cf3e80dfSAndrew Lunn 
614e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_access_c22(struct mv88e6xxx_chip *chip,
615e289ef0dSVivien Didelot 					   bool external, u16 op, int dev,
616e289ef0dSVivien Didelot 					   int reg)
617cf3e80dfSAndrew Lunn {
618e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_access(chip, external, false, op, dev, reg);
619cf3e80dfSAndrew Lunn }
620cf3e80dfSAndrew Lunn 
621e289ef0dSVivien Didelot /* IEEE 802.3 Clause 22 Read Data Register */
622e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_read_data_c22(struct mv88e6xxx_chip *chip,
623e289ef0dSVivien Didelot 					      bool external, int dev, int reg,
624e289ef0dSVivien Didelot 					      u16 *data)
625cf3e80dfSAndrew Lunn {
626e289ef0dSVivien Didelot 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_READ_DATA;
627cf3e80dfSAndrew Lunn 	int err;
628cf3e80dfSAndrew Lunn 
629ec561276SVivien Didelot 	err = mv88e6xxx_g2_smi_phy_wait(chip);
630ec561276SVivien Didelot 	if (err)
631ec561276SVivien Didelot 		return err;
632ec561276SVivien Didelot 
633e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
634ec561276SVivien Didelot 	if (err)
635ec561276SVivien Didelot 		return err;
636ec561276SVivien Didelot 
637e289ef0dSVivien Didelot 	return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
638ec561276SVivien Didelot }
639ec561276SVivien Didelot 
640e289ef0dSVivien Didelot /* IEEE 802.3 Clause 22 Write Data Register */
641e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_data_c22(struct mv88e6xxx_chip *chip,
642e289ef0dSVivien Didelot 					       bool external, int dev, int reg,
643e289ef0dSVivien Didelot 					       u16 data)
644e289ef0dSVivien Didelot {
645e289ef0dSVivien Didelot 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_WRITE_DATA;
646e289ef0dSVivien Didelot 	int err;
647e289ef0dSVivien Didelot 
648e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_smi_phy_wait(chip);
649e289ef0dSVivien Didelot 	if (err)
650e289ef0dSVivien Didelot 		return err;
651e289ef0dSVivien Didelot 
652e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
653e289ef0dSVivien Didelot 	if (err)
654e289ef0dSVivien Didelot 		return err;
655e289ef0dSVivien Didelot 
656e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
657e289ef0dSVivien Didelot }
658e289ef0dSVivien Didelot 
659e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_access_c45(struct mv88e6xxx_chip *chip,
660e289ef0dSVivien Didelot 					   bool external, u16 op, int port,
661e289ef0dSVivien Didelot 					   int dev)
662e289ef0dSVivien Didelot {
663e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_access(chip, external, true, op, port, dev);
664e289ef0dSVivien Didelot }
665e289ef0dSVivien Didelot 
666e289ef0dSVivien Didelot /* IEEE 802.3 Clause 45 Write Address Register */
667e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_addr_c45(struct mv88e6xxx_chip *chip,
668e289ef0dSVivien Didelot 					       bool external, int port, int dev,
669e289ef0dSVivien Didelot 					       int addr)
670e289ef0dSVivien Didelot {
671e289ef0dSVivien Didelot 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_ADDR;
672e289ef0dSVivien Didelot 	int err;
673e289ef0dSVivien Didelot 
674e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_smi_phy_wait(chip);
675e289ef0dSVivien Didelot 	if (err)
676e289ef0dSVivien Didelot 		return err;
677e289ef0dSVivien Didelot 
678e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, addr);
679e289ef0dSVivien Didelot 	if (err)
680e289ef0dSVivien Didelot 		return err;
681e289ef0dSVivien Didelot 
682e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
683e289ef0dSVivien Didelot }
684e289ef0dSVivien Didelot 
685e289ef0dSVivien Didelot /* IEEE 802.3 Clause 45 Read Data Register */
686e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_read_data_c45(struct mv88e6xxx_chip *chip,
687e289ef0dSVivien Didelot 					      bool external, int port, int dev,
688e289ef0dSVivien Didelot 					      u16 *data)
689e289ef0dSVivien Didelot {
690e289ef0dSVivien Didelot 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_READ_DATA;
691e289ef0dSVivien Didelot 	int err;
692e289ef0dSVivien Didelot 
693e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
694e289ef0dSVivien Didelot 	if (err)
695e289ef0dSVivien Didelot 		return err;
696e289ef0dSVivien Didelot 
697e289ef0dSVivien Didelot 	return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
698e289ef0dSVivien Didelot }
699e289ef0dSVivien Didelot 
700e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip,
701e289ef0dSVivien Didelot 					 bool external, int port, int reg,
702e289ef0dSVivien Didelot 					 u16 *data)
703e289ef0dSVivien Didelot {
704e289ef0dSVivien Didelot 	int dev = (reg >> 16) & 0x1f;
705e289ef0dSVivien Didelot 	int addr = reg & 0xffff;
706e289ef0dSVivien Didelot 	int err;
707e289ef0dSVivien Didelot 
708e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev,
709e289ef0dSVivien Didelot 						  addr);
710e289ef0dSVivien Didelot 	if (err)
711e289ef0dSVivien Didelot 		return err;
712e289ef0dSVivien Didelot 
713e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_read_data_c45(chip, external, port, dev,
714e289ef0dSVivien Didelot 						  data);
715e289ef0dSVivien Didelot }
716e289ef0dSVivien Didelot 
717e289ef0dSVivien Didelot /* IEEE 802.3 Clause 45 Write Data Register */
718e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_data_c45(struct mv88e6xxx_chip *chip,
719e289ef0dSVivien Didelot 					       bool external, int port, int dev,
720e289ef0dSVivien Didelot 					       u16 data)
721e289ef0dSVivien Didelot {
722e289ef0dSVivien Didelot 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_DATA;
723e289ef0dSVivien Didelot 	int err;
724e289ef0dSVivien Didelot 
725e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
726e289ef0dSVivien Didelot 	if (err)
727e289ef0dSVivien Didelot 		return err;
728e289ef0dSVivien Didelot 
729e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
730e289ef0dSVivien Didelot }
731e289ef0dSVivien Didelot 
732e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip,
733e289ef0dSVivien Didelot 					  bool external, int port, int reg,
734e289ef0dSVivien Didelot 					  u16 data)
735e289ef0dSVivien Didelot {
736e289ef0dSVivien Didelot 	int dev = (reg >> 16) & 0x1f;
737e289ef0dSVivien Didelot 	int addr = reg & 0xffff;
738e289ef0dSVivien Didelot 	int err;
739e289ef0dSVivien Didelot 
740e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev,
741e289ef0dSVivien Didelot 						  addr);
742e289ef0dSVivien Didelot 	if (err)
743e289ef0dSVivien Didelot 		return err;
744e289ef0dSVivien Didelot 
745e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_write_data_c45(chip, external, port, dev,
746e289ef0dSVivien Didelot 						   data);
747e289ef0dSVivien Didelot }
748e289ef0dSVivien Didelot 
749e289ef0dSVivien Didelot int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
750cf3e80dfSAndrew Lunn 			      int addr, int reg, u16 *val)
751cf3e80dfSAndrew Lunn {
752cf3e80dfSAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
753cf3e80dfSAndrew Lunn 	bool external = mdio_bus->external;
754cf3e80dfSAndrew Lunn 
755cf3e80dfSAndrew Lunn 	if (reg & MII_ADDR_C45)
756e289ef0dSVivien Didelot 		return mv88e6xxx_g2_smi_phy_read_c45(chip, external, addr, reg,
757e289ef0dSVivien Didelot 						     val);
758e289ef0dSVivien Didelot 
759e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_read_data_c22(chip, external, addr, reg,
760e289ef0dSVivien Didelot 						  val);
761cf3e80dfSAndrew Lunn }
762cf3e80dfSAndrew Lunn 
763e289ef0dSVivien Didelot int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
764cf3e80dfSAndrew Lunn 			       int addr, int reg, u16 val)
765cf3e80dfSAndrew Lunn {
766cf3e80dfSAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
767cf3e80dfSAndrew Lunn 	bool external = mdio_bus->external;
768cf3e80dfSAndrew Lunn 
769cf3e80dfSAndrew Lunn 	if (reg & MII_ADDR_C45)
770e289ef0dSVivien Didelot 		return mv88e6xxx_g2_smi_phy_write_c45(chip, external, addr, reg,
771e289ef0dSVivien Didelot 						      val);
772cf3e80dfSAndrew Lunn 
773e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_write_data_c22(chip, external, addr, reg,
774e289ef0dSVivien Didelot 						   val);
775cf3e80dfSAndrew Lunn }
776cf3e80dfSAndrew Lunn 
777a73ccd61SBrandon Streiff /* Offset 0x1B: Watchdog Control */
778fcd25166SAndrew Lunn static int mv88e6097_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
779fcd25166SAndrew Lunn {
780fcd25166SAndrew Lunn 	u16 reg;
781fcd25166SAndrew Lunn 
7823b19df73SVivien Didelot 	mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, &reg);
783fcd25166SAndrew Lunn 
784fcd25166SAndrew Lunn 	dev_info(chip->dev, "Watchdog event: 0x%04x", reg);
785fcd25166SAndrew Lunn 
786fcd25166SAndrew Lunn 	return IRQ_HANDLED;
787fcd25166SAndrew Lunn }
788fcd25166SAndrew Lunn 
789fcd25166SAndrew Lunn static void mv88e6097_watchdog_free(struct mv88e6xxx_chip *chip)
790fcd25166SAndrew Lunn {
791fcd25166SAndrew Lunn 	u16 reg;
792fcd25166SAndrew Lunn 
7933b19df73SVivien Didelot 	mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, &reg);
794fcd25166SAndrew Lunn 
7953b19df73SVivien Didelot 	reg &= ~(MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
7963b19df73SVivien Didelot 		 MV88E6352_G2_WDOG_CTL_QC_ENABLE);
797fcd25166SAndrew Lunn 
7983b19df73SVivien Didelot 	mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL, reg);
799fcd25166SAndrew Lunn }
800fcd25166SAndrew Lunn 
801fcd25166SAndrew Lunn static int mv88e6097_watchdog_setup(struct mv88e6xxx_chip *chip)
802fcd25166SAndrew Lunn {
8033b19df73SVivien Didelot 	return mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL,
8043b19df73SVivien Didelot 				  MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
8053b19df73SVivien Didelot 				  MV88E6352_G2_WDOG_CTL_QC_ENABLE |
8063b19df73SVivien Didelot 				  MV88E6352_G2_WDOG_CTL_SWRESET);
807fcd25166SAndrew Lunn }
808fcd25166SAndrew Lunn 
809fcd25166SAndrew Lunn const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {
810fcd25166SAndrew Lunn 	.irq_action = mv88e6097_watchdog_action,
811fcd25166SAndrew Lunn 	.irq_setup = mv88e6097_watchdog_setup,
812fcd25166SAndrew Lunn 	.irq_free = mv88e6097_watchdog_free,
813fcd25166SAndrew Lunn };
814fcd25166SAndrew Lunn 
81561303736SAndrew Lunn static int mv88e6390_watchdog_setup(struct mv88e6xxx_chip *chip)
81661303736SAndrew Lunn {
8173b19df73SVivien Didelot 	return mv88e6xxx_g2_update(chip, MV88E6390_G2_WDOG_CTL,
8183b19df73SVivien Didelot 				   MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE |
8193b19df73SVivien Didelot 				   MV88E6390_G2_WDOG_CTL_CUT_THROUGH |
8203b19df73SVivien Didelot 				   MV88E6390_G2_WDOG_CTL_QUEUE_CONTROLLER |
8213b19df73SVivien Didelot 				   MV88E6390_G2_WDOG_CTL_EGRESS |
8223b19df73SVivien Didelot 				   MV88E6390_G2_WDOG_CTL_FORCE_IRQ);
82361303736SAndrew Lunn }
82461303736SAndrew Lunn 
82561303736SAndrew Lunn static int mv88e6390_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
82661303736SAndrew Lunn {
82761303736SAndrew Lunn 	int err;
82861303736SAndrew Lunn 	u16 reg;
82961303736SAndrew Lunn 
8303b19df73SVivien Didelot 	mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
8313b19df73SVivien Didelot 			   MV88E6390_G2_WDOG_CTL_PTR_EVENT);
8323b19df73SVivien Didelot 	err = mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, &reg);
83361303736SAndrew Lunn 
83461303736SAndrew Lunn 	dev_info(chip->dev, "Watchdog event: 0x%04x",
8353b19df73SVivien Didelot 		 reg & MV88E6390_G2_WDOG_CTL_DATA_MASK);
83661303736SAndrew Lunn 
8373b19df73SVivien Didelot 	mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
8383b19df73SVivien Didelot 			   MV88E6390_G2_WDOG_CTL_PTR_HISTORY);
8393b19df73SVivien Didelot 	err = mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, &reg);
84061303736SAndrew Lunn 
84161303736SAndrew Lunn 	dev_info(chip->dev, "Watchdog history: 0x%04x",
8423b19df73SVivien Didelot 		 reg & MV88E6390_G2_WDOG_CTL_DATA_MASK);
84361303736SAndrew Lunn 
84461303736SAndrew Lunn 	/* Trigger a software reset to try to recover the switch */
84561303736SAndrew Lunn 	if (chip->info->ops->reset)
84661303736SAndrew Lunn 		chip->info->ops->reset(chip);
84761303736SAndrew Lunn 
84861303736SAndrew Lunn 	mv88e6390_watchdog_setup(chip);
84961303736SAndrew Lunn 
85061303736SAndrew Lunn 	return IRQ_HANDLED;
85161303736SAndrew Lunn }
85261303736SAndrew Lunn 
85361303736SAndrew Lunn static void mv88e6390_watchdog_free(struct mv88e6xxx_chip *chip)
85461303736SAndrew Lunn {
8553b19df73SVivien Didelot 	mv88e6xxx_g2_update(chip, MV88E6390_G2_WDOG_CTL,
8563b19df73SVivien Didelot 			    MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE);
85761303736SAndrew Lunn }
85861303736SAndrew Lunn 
85961303736SAndrew Lunn const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {
86061303736SAndrew Lunn 	.irq_action = mv88e6390_watchdog_action,
86161303736SAndrew Lunn 	.irq_setup = mv88e6390_watchdog_setup,
86261303736SAndrew Lunn 	.irq_free = mv88e6390_watchdog_free,
86361303736SAndrew Lunn };
86461303736SAndrew Lunn 
865fcd25166SAndrew Lunn static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id)
866fcd25166SAndrew Lunn {
867fcd25166SAndrew Lunn 	struct mv88e6xxx_chip *chip = dev_id;
868fcd25166SAndrew Lunn 	irqreturn_t ret = IRQ_NONE;
869fcd25166SAndrew Lunn 
870fcd25166SAndrew Lunn 	mutex_lock(&chip->reg_lock);
871fcd25166SAndrew Lunn 	if (chip->info->ops->watchdog_ops->irq_action)
872fcd25166SAndrew Lunn 		ret = chip->info->ops->watchdog_ops->irq_action(chip, irq);
873fcd25166SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
874fcd25166SAndrew Lunn 
875fcd25166SAndrew Lunn 	return ret;
876fcd25166SAndrew Lunn }
877fcd25166SAndrew Lunn 
878fcd25166SAndrew Lunn static void mv88e6xxx_g2_watchdog_free(struct mv88e6xxx_chip *chip)
879fcd25166SAndrew Lunn {
880fcd25166SAndrew Lunn 	mutex_lock(&chip->reg_lock);
881fcd25166SAndrew Lunn 	if (chip->info->ops->watchdog_ops->irq_free)
882fcd25166SAndrew Lunn 		chip->info->ops->watchdog_ops->irq_free(chip);
883fcd25166SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
884fcd25166SAndrew Lunn 
885fcd25166SAndrew Lunn 	free_irq(chip->watchdog_irq, chip);
886fcd25166SAndrew Lunn 	irq_dispose_mapping(chip->watchdog_irq);
887fcd25166SAndrew Lunn }
888fcd25166SAndrew Lunn 
889fcd25166SAndrew Lunn static int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip)
890fcd25166SAndrew Lunn {
891fcd25166SAndrew Lunn 	int err;
892fcd25166SAndrew Lunn 
893fcd25166SAndrew Lunn 	chip->watchdog_irq = irq_find_mapping(chip->g2_irq.domain,
8941d90016dSVivien Didelot 					      MV88E6XXX_G2_INT_SOURCE_WATCHDOG);
895fcd25166SAndrew Lunn 	if (chip->watchdog_irq < 0)
896fcd25166SAndrew Lunn 		return chip->watchdog_irq;
897fcd25166SAndrew Lunn 
898fcd25166SAndrew Lunn 	err = request_threaded_irq(chip->watchdog_irq, NULL,
899fcd25166SAndrew Lunn 				   mv88e6xxx_g2_watchdog_thread_fn,
900fcd25166SAndrew Lunn 				   IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
901fcd25166SAndrew Lunn 				   "mv88e6xxx-watchdog", chip);
902fcd25166SAndrew Lunn 	if (err)
903fcd25166SAndrew Lunn 		return err;
904fcd25166SAndrew Lunn 
905fcd25166SAndrew Lunn 	mutex_lock(&chip->reg_lock);
906fcd25166SAndrew Lunn 	if (chip->info->ops->watchdog_ops->irq_setup)
907fcd25166SAndrew Lunn 		err = chip->info->ops->watchdog_ops->irq_setup(chip);
908fcd25166SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
909fcd25166SAndrew Lunn 
910fcd25166SAndrew Lunn 	return err;
911fcd25166SAndrew Lunn }
912fcd25166SAndrew Lunn 
91381228996SVivien Didelot /* Offset 0x1D: Misc Register */
91481228996SVivien Didelot 
91581228996SVivien Didelot static int mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip *chip,
91681228996SVivien Didelot 					bool port_5_bit)
91781228996SVivien Didelot {
91881228996SVivien Didelot 	u16 val;
91981228996SVivien Didelot 	int err;
92081228996SVivien Didelot 
9211d90016dSVivien Didelot 	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_MISC, &val);
92281228996SVivien Didelot 	if (err)
92381228996SVivien Didelot 		return err;
92481228996SVivien Didelot 
92581228996SVivien Didelot 	if (port_5_bit)
9261d90016dSVivien Didelot 		val |= MV88E6XXX_G2_MISC_5_BIT_PORT;
92781228996SVivien Didelot 	else
9281d90016dSVivien Didelot 		val &= ~MV88E6XXX_G2_MISC_5_BIT_PORT;
92981228996SVivien Didelot 
9301d90016dSVivien Didelot 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MISC, val);
93181228996SVivien Didelot }
93281228996SVivien Didelot 
93381228996SVivien Didelot int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip)
93481228996SVivien Didelot {
93581228996SVivien Didelot 	return mv88e6xxx_g2_misc_5_bit_port(chip, false);
93681228996SVivien Didelot }
93781228996SVivien Didelot 
938dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_mask(struct irq_data *d)
939dc30c35bSAndrew Lunn {
940dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
941dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
942dc30c35bSAndrew Lunn 
943dc30c35bSAndrew Lunn 	chip->g2_irq.masked |= (1 << n);
944dc30c35bSAndrew Lunn }
945dc30c35bSAndrew Lunn 
946dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_unmask(struct irq_data *d)
947dc30c35bSAndrew Lunn {
948dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
949dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
950dc30c35bSAndrew Lunn 
951dc30c35bSAndrew Lunn 	chip->g2_irq.masked &= ~(1 << n);
952dc30c35bSAndrew Lunn }
953dc30c35bSAndrew Lunn 
954dc30c35bSAndrew Lunn static irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id)
955dc30c35bSAndrew Lunn {
956dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = dev_id;
957dc30c35bSAndrew Lunn 	unsigned int nhandled = 0;
958dc30c35bSAndrew Lunn 	unsigned int sub_irq;
959dc30c35bSAndrew Lunn 	unsigned int n;
960dc30c35bSAndrew Lunn 	int err;
961dc30c35bSAndrew Lunn 	u16 reg;
962dc30c35bSAndrew Lunn 
963dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
964d6c5e6afSVivien Didelot 	err = mv88e6xxx_g2_int_source(chip, &reg);
965dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
966dc30c35bSAndrew Lunn 	if (err)
967dc30c35bSAndrew Lunn 		goto out;
968dc30c35bSAndrew Lunn 
969dc30c35bSAndrew Lunn 	for (n = 0; n < 16; ++n) {
970dc30c35bSAndrew Lunn 		if (reg & (1 << n)) {
971dc30c35bSAndrew Lunn 			sub_irq = irq_find_mapping(chip->g2_irq.domain, n);
972dc30c35bSAndrew Lunn 			handle_nested_irq(sub_irq);
973dc30c35bSAndrew Lunn 			++nhandled;
974dc30c35bSAndrew Lunn 		}
975dc30c35bSAndrew Lunn 	}
976dc30c35bSAndrew Lunn out:
977dc30c35bSAndrew Lunn 	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
978dc30c35bSAndrew Lunn }
979dc30c35bSAndrew Lunn 
980dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_bus_lock(struct irq_data *d)
981dc30c35bSAndrew Lunn {
982dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
983dc30c35bSAndrew Lunn 
984dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
985dc30c35bSAndrew Lunn }
986dc30c35bSAndrew Lunn 
987dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d)
988dc30c35bSAndrew Lunn {
989dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
990d6c5e6afSVivien Didelot 	int err;
991dc30c35bSAndrew Lunn 
992d6c5e6afSVivien Didelot 	err = mv88e6xxx_g2_int_mask(chip, ~chip->g2_irq.masked);
993d6c5e6afSVivien Didelot 	if (err)
994d6c5e6afSVivien Didelot 		dev_err(chip->dev, "failed to mask interrupts\n");
995dc30c35bSAndrew Lunn 
996dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
997dc30c35bSAndrew Lunn }
998dc30c35bSAndrew Lunn 
9996eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g2_irq_chip = {
1000dc30c35bSAndrew Lunn 	.name			= "mv88e6xxx-g2",
1001dc30c35bSAndrew Lunn 	.irq_mask		= mv88e6xxx_g2_irq_mask,
1002dc30c35bSAndrew Lunn 	.irq_unmask		= mv88e6xxx_g2_irq_unmask,
1003dc30c35bSAndrew Lunn 	.irq_bus_lock		= mv88e6xxx_g2_irq_bus_lock,
1004dc30c35bSAndrew Lunn 	.irq_bus_sync_unlock	= mv88e6xxx_g2_irq_bus_sync_unlock,
1005dc30c35bSAndrew Lunn };
1006dc30c35bSAndrew Lunn 
1007dc30c35bSAndrew Lunn static int mv88e6xxx_g2_irq_domain_map(struct irq_domain *d,
1008dc30c35bSAndrew Lunn 				       unsigned int irq,
1009dc30c35bSAndrew Lunn 				       irq_hw_number_t hwirq)
1010dc30c35bSAndrew Lunn {
1011dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = d->host_data;
1012dc30c35bSAndrew Lunn 
1013dc30c35bSAndrew Lunn 	irq_set_chip_data(irq, d->host_data);
1014dc30c35bSAndrew Lunn 	irq_set_chip_and_handler(irq, &chip->g2_irq.chip, handle_level_irq);
1015dc30c35bSAndrew Lunn 	irq_set_noprobe(irq);
1016dc30c35bSAndrew Lunn 
1017dc30c35bSAndrew Lunn 	return 0;
1018dc30c35bSAndrew Lunn }
1019dc30c35bSAndrew Lunn 
1020dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g2_irq_domain_ops = {
1021dc30c35bSAndrew Lunn 	.map	= mv88e6xxx_g2_irq_domain_map,
1022dc30c35bSAndrew Lunn 	.xlate	= irq_domain_xlate_twocell,
1023dc30c35bSAndrew Lunn };
1024dc30c35bSAndrew Lunn 
1025dc30c35bSAndrew Lunn void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip)
1026dc30c35bSAndrew Lunn {
1027dc30c35bSAndrew Lunn 	int irq, virq;
1028dc30c35bSAndrew Lunn 
1029fcd25166SAndrew Lunn 	mv88e6xxx_g2_watchdog_free(chip);
1030fcd25166SAndrew Lunn 
10318e757ebaSAndrew Lunn 	free_irq(chip->device_irq, chip);
10328e757ebaSAndrew Lunn 	irq_dispose_mapping(chip->device_irq);
10338e757ebaSAndrew Lunn 
1034dc30c35bSAndrew Lunn 	for (irq = 0; irq < 16; irq++) {
1035dc30c35bSAndrew Lunn 		virq = irq_find_mapping(chip->g2_irq.domain, irq);
1036dc30c35bSAndrew Lunn 		irq_dispose_mapping(virq);
1037dc30c35bSAndrew Lunn 	}
1038dc30c35bSAndrew Lunn 
1039dc30c35bSAndrew Lunn 	irq_domain_remove(chip->g2_irq.domain);
1040dc30c35bSAndrew Lunn }
1041dc30c35bSAndrew Lunn 
1042dc30c35bSAndrew Lunn int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip)
1043dc30c35bSAndrew Lunn {
10448e757ebaSAndrew Lunn 	int err, irq, virq;
1045dc30c35bSAndrew Lunn 
1046dc30c35bSAndrew Lunn 	chip->g2_irq.domain = irq_domain_add_simple(
1047dc30c35bSAndrew Lunn 		chip->dev->of_node, 16, 0, &mv88e6xxx_g2_irq_domain_ops, chip);
1048dc30c35bSAndrew Lunn 	if (!chip->g2_irq.domain)
1049dc30c35bSAndrew Lunn 		return -ENOMEM;
1050dc30c35bSAndrew Lunn 
1051dc30c35bSAndrew Lunn 	for (irq = 0; irq < 16; irq++)
1052dc30c35bSAndrew Lunn 		irq_create_mapping(chip->g2_irq.domain, irq);
1053dc30c35bSAndrew Lunn 
1054dc30c35bSAndrew Lunn 	chip->g2_irq.chip = mv88e6xxx_g2_irq_chip;
1055dc30c35bSAndrew Lunn 	chip->g2_irq.masked = ~0;
1056dc30c35bSAndrew Lunn 
10578e757ebaSAndrew Lunn 	chip->device_irq = irq_find_mapping(chip->g1_irq.domain,
105882466921SVivien Didelot 					    MV88E6XXX_G1_STS_IRQ_DEVICE);
10598e757ebaSAndrew Lunn 	if (chip->device_irq < 0) {
10608e757ebaSAndrew Lunn 		err = chip->device_irq;
1061dc30c35bSAndrew Lunn 		goto out;
1062dc30c35bSAndrew Lunn 	}
1063dc30c35bSAndrew Lunn 
10648e757ebaSAndrew Lunn 	err = request_threaded_irq(chip->device_irq, NULL,
1065dc30c35bSAndrew Lunn 				   mv88e6xxx_g2_irq_thread_fn,
106636d6ea94SUwe Kleine-König 				   IRQF_ONESHOT, "mv88e6xxx-g2", chip);
1067dc30c35bSAndrew Lunn 	if (err)
1068dc30c35bSAndrew Lunn 		goto out;
1069dc30c35bSAndrew Lunn 
1070fcd25166SAndrew Lunn 	return mv88e6xxx_g2_watchdog_setup(chip);
10718e757ebaSAndrew Lunn 
1072dc30c35bSAndrew Lunn out:
10738e757ebaSAndrew Lunn 	for (irq = 0; irq < 16; irq++) {
10748e757ebaSAndrew Lunn 		virq = irq_find_mapping(chip->g2_irq.domain, irq);
10758e757ebaSAndrew Lunn 		irq_dispose_mapping(virq);
10768e757ebaSAndrew Lunn 	}
10778e757ebaSAndrew Lunn 
10788e757ebaSAndrew Lunn 	irq_domain_remove(chip->g2_irq.domain);
1079dc30c35bSAndrew Lunn 
1080dc30c35bSAndrew Lunn 	return err;
1081dc30c35bSAndrew Lunn }
1082dc30c35bSAndrew Lunn 
10836f88284fSAndrew Lunn int mv88e6xxx_g2_irq_mdio_setup(struct mv88e6xxx_chip *chip,
10846f88284fSAndrew Lunn 				struct mii_bus *bus)
10856f88284fSAndrew Lunn {
10866f88284fSAndrew Lunn 	int phy, irq, err, err_phy;
10876f88284fSAndrew Lunn 
10886f88284fSAndrew Lunn 	for (phy = 0; phy < chip->info->num_internal_phys; phy++) {
10896f88284fSAndrew Lunn 		irq = irq_find_mapping(chip->g2_irq.domain, phy);
10906f88284fSAndrew Lunn 		if (irq < 0) {
10916f88284fSAndrew Lunn 			err = irq;
10926f88284fSAndrew Lunn 			goto out;
10936f88284fSAndrew Lunn 		}
10949255bacdSAndrew Lunn 		bus->irq[chip->info->phy_base_addr + phy] = irq;
10956f88284fSAndrew Lunn 	}
10966f88284fSAndrew Lunn 	return 0;
10976f88284fSAndrew Lunn out:
10986f88284fSAndrew Lunn 	err_phy = phy;
10996f88284fSAndrew Lunn 
11006f88284fSAndrew Lunn 	for (phy = 0; phy < err_phy; phy++)
11016f88284fSAndrew Lunn 		irq_dispose_mapping(bus->irq[phy]);
11026f88284fSAndrew Lunn 
11036f88284fSAndrew Lunn 	return err;
11046f88284fSAndrew Lunn }
11056f88284fSAndrew Lunn 
11066f88284fSAndrew Lunn void mv88e6xxx_g2_irq_mdio_free(struct mv88e6xxx_chip *chip,
11076f88284fSAndrew Lunn 				struct mii_bus *bus)
11086f88284fSAndrew Lunn {
11096f88284fSAndrew Lunn 	int phy;
11106f88284fSAndrew Lunn 
11116f88284fSAndrew Lunn 	for (phy = 0; phy < chip->info->num_internal_phys; phy++)
11126f88284fSAndrew Lunn 		irq_dispose_mapping(bus->irq[phy]);
11136f88284fSAndrew Lunn }
1114