1ec561276SVivien Didelot /*
2dc30c35bSAndrew Lunn  * Marvell 88E6xxx Switch Global 2 Registers support (device address
3dc30c35bSAndrew Lunn  * 0x1C)
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  * This program is free software; you can redistribute it and/or modify
11ec561276SVivien Didelot  * it under the terms of the GNU General Public License as published by
12ec561276SVivien Didelot  * the Free Software Foundation; either version 2 of the License, or
13ec561276SVivien Didelot  * (at your option) any later version.
14ec561276SVivien Didelot  */
15ec561276SVivien Didelot 
16e289ef0dSVivien Didelot #include <linux/bitfield.h>
17282ccf6eSFlorian Westphal #include <linux/interrupt.h>
18dc30c35bSAndrew Lunn #include <linux/irqdomain.h>
194d5f2ba7SVivien Didelot 
204d5f2ba7SVivien Didelot #include "chip.h"
2182466921SVivien Didelot #include "global1.h" /* for MV88E6XXX_G1_STS_IRQ_DEVICE */
22ec561276SVivien Didelot #include "global2.h"
23ec561276SVivien Didelot 
249fe850fbSVivien Didelot static int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
259fe850fbSVivien Didelot {
269fe850fbSVivien Didelot 	return mv88e6xxx_read(chip, ADDR_GLOBAL2, reg, val);
279fe850fbSVivien Didelot }
289fe850fbSVivien Didelot 
299fe850fbSVivien Didelot static int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
309fe850fbSVivien Didelot {
319fe850fbSVivien Didelot 	return mv88e6xxx_write(chip, ADDR_GLOBAL2, reg, val);
329fe850fbSVivien Didelot }
339fe850fbSVivien Didelot 
349fe850fbSVivien Didelot static int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update)
359fe850fbSVivien Didelot {
369fe850fbSVivien Didelot 	return mv88e6xxx_update(chip, ADDR_GLOBAL2, reg, update);
379fe850fbSVivien Didelot }
389fe850fbSVivien Didelot 
399fe850fbSVivien Didelot static int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
409fe850fbSVivien Didelot {
419fe850fbSVivien Didelot 	return mv88e6xxx_wait(chip, ADDR_GLOBAL2, reg, mask);
429fe850fbSVivien Didelot }
439fe850fbSVivien Didelot 
446e55f698SAndrew Lunn /* Offset 0x02: Management Enable 2x */
456e55f698SAndrew Lunn /* Offset 0x03: Management Enable 0x */
466e55f698SAndrew Lunn 
476e55f698SAndrew Lunn int mv88e6095_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
486e55f698SAndrew Lunn {
496e55f698SAndrew Lunn 	int err;
506e55f698SAndrew Lunn 
516e55f698SAndrew Lunn 	/* Consider the frames with reserved multicast destination
526e55f698SAndrew Lunn 	 * addresses matching 01:80:c2:00:00:2x as MGMT.
536e55f698SAndrew Lunn 	 */
546e55f698SAndrew Lunn 	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X)) {
556e55f698SAndrew Lunn 		err = mv88e6xxx_g2_write(chip, GLOBAL2_MGMT_EN_2X, 0xffff);
566e55f698SAndrew Lunn 		if (err)
576e55f698SAndrew Lunn 			return err;
586e55f698SAndrew Lunn 	}
596e55f698SAndrew Lunn 
606e55f698SAndrew Lunn 	/* Consider the frames with reserved multicast destination
616e55f698SAndrew Lunn 	 * addresses matching 01:80:c2:00:00:0x as MGMT.
626e55f698SAndrew Lunn 	 */
636e55f698SAndrew Lunn 	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X))
646e55f698SAndrew Lunn 		return mv88e6xxx_g2_write(chip, GLOBAL2_MGMT_EN_0X, 0xffff);
656e55f698SAndrew Lunn 
666e55f698SAndrew Lunn 	return 0;
676e55f698SAndrew Lunn }
686e55f698SAndrew Lunn 
69ec561276SVivien Didelot /* Offset 0x06: Device Mapping Table register */
70ec561276SVivien Didelot 
71ec561276SVivien Didelot static int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip,
72ec561276SVivien Didelot 					     int target, int port)
73ec561276SVivien Didelot {
74ec561276SVivien Didelot 	u16 val = (target << 8) | (port & 0xf);
75ec561276SVivien Didelot 
76067e474aSVivien Didelot 	return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_DEVICE_MAPPING, val);
77ec561276SVivien Didelot }
78ec561276SVivien Didelot 
79ec561276SVivien Didelot static int mv88e6xxx_g2_set_device_mapping(struct mv88e6xxx_chip *chip)
80ec561276SVivien Didelot {
81ec561276SVivien Didelot 	int target, port;
82ec561276SVivien Didelot 	int err;
83ec561276SVivien Didelot 
84ec561276SVivien Didelot 	/* Initialize the routing port to the 32 possible target devices */
85ec561276SVivien Didelot 	for (target = 0; target < 32; ++target) {
86ec561276SVivien Didelot 		port = 0xf;
87ec561276SVivien Didelot 
88ec561276SVivien Didelot 		if (target < DSA_MAX_SWITCHES) {
89ec561276SVivien Didelot 			port = chip->ds->rtable[target];
90ec561276SVivien Didelot 			if (port == DSA_RTABLE_NONE)
91ec561276SVivien Didelot 				port = 0xf;
92ec561276SVivien Didelot 		}
93ec561276SVivien Didelot 
94ec561276SVivien Didelot 		err = mv88e6xxx_g2_device_mapping_write(chip, target, port);
95ec561276SVivien Didelot 		if (err)
96ec561276SVivien Didelot 			break;
97ec561276SVivien Didelot 	}
98ec561276SVivien Didelot 
99ec561276SVivien Didelot 	return err;
100ec561276SVivien Didelot }
101ec561276SVivien Didelot 
102ec561276SVivien Didelot /* Offset 0x07: Trunk Mask Table register */
103ec561276SVivien Didelot 
104ec561276SVivien Didelot static int mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip *chip, int num,
10556dc7347SVivien Didelot 					 bool hash, u16 mask)
106ec561276SVivien Didelot {
10756dc7347SVivien Didelot 	u16 val = (num << 12) | (mask & mv88e6xxx_port_mask(chip));
108ec561276SVivien Didelot 
10956dc7347SVivien Didelot 	if (hash)
11056dc7347SVivien Didelot 		val |= MV88E6XXX_G2_TRUNK_MASK_HASH;
111ec561276SVivien Didelot 
11256dc7347SVivien Didelot 	return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_TRUNK_MASK, val);
113ec561276SVivien Didelot }
114ec561276SVivien Didelot 
115ec561276SVivien Didelot /* Offset 0x08: Trunk Mapping Table register */
116ec561276SVivien Didelot 
117ec561276SVivien Didelot static int mv88e6xxx_g2_trunk_mapping_write(struct mv88e6xxx_chip *chip, int id,
118ec561276SVivien Didelot 					    u16 map)
119ec561276SVivien Didelot {
120370b4ffbSVivien Didelot 	const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
121ec561276SVivien Didelot 	u16 val = (id << 11) | (map & port_mask);
122ec561276SVivien Didelot 
12356dc7347SVivien Didelot 	return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_TRUNK_MAPPING, val);
124ec561276SVivien Didelot }
125ec561276SVivien Didelot 
126ec561276SVivien Didelot static int mv88e6xxx_g2_clear_trunk(struct mv88e6xxx_chip *chip)
127ec561276SVivien Didelot {
128370b4ffbSVivien Didelot 	const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
129ec561276SVivien Didelot 	int i, err;
130ec561276SVivien Didelot 
131ec561276SVivien Didelot 	/* Clear all eight possible Trunk Mask vectors */
132ec561276SVivien Didelot 	for (i = 0; i < 8; ++i) {
133ec561276SVivien Didelot 		err = mv88e6xxx_g2_trunk_mask_write(chip, i, false, port_mask);
134ec561276SVivien Didelot 		if (err)
135ec561276SVivien Didelot 			return err;
136ec561276SVivien Didelot 	}
137ec561276SVivien Didelot 
138ec561276SVivien Didelot 	/* Clear all sixteen possible Trunk ID routing vectors */
139ec561276SVivien Didelot 	for (i = 0; i < 16; ++i) {
140ec561276SVivien Didelot 		err = mv88e6xxx_g2_trunk_mapping_write(chip, i, 0);
141ec561276SVivien Didelot 		if (err)
142ec561276SVivien Didelot 			return err;
143ec561276SVivien Didelot 	}
144ec561276SVivien Didelot 
145ec561276SVivien Didelot 	return 0;
146ec561276SVivien Didelot }
147ec561276SVivien Didelot 
148ec561276SVivien Didelot /* Offset 0x09: Ingress Rate Command register
149ec561276SVivien Didelot  * Offset 0x0A: Ingress Rate Data register
150ec561276SVivien Didelot  */
151ec561276SVivien Didelot 
152cd8da8bbSVivien Didelot static int mv88e6xxx_g2_irl_wait(struct mv88e6xxx_chip *chip)
153ec561276SVivien Didelot {
154cd8da8bbSVivien Didelot 	return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_IRL_CMD,
155cd8da8bbSVivien Didelot 				 MV88E6XXX_G2_IRL_CMD_BUSY);
156ec561276SVivien Didelot }
157ec561276SVivien Didelot 
158cd8da8bbSVivien Didelot static int mv88e6xxx_g2_irl_op(struct mv88e6xxx_chip *chip, u16 op, int port,
159cd8da8bbSVivien Didelot 			       int res, int reg)
160cd8da8bbSVivien Didelot {
161cd8da8bbSVivien Didelot 	int err;
162cd8da8bbSVivien Didelot 
163cd8da8bbSVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_IRL_CMD,
164cd8da8bbSVivien Didelot 				 MV88E6XXX_G2_IRL_CMD_BUSY | op | (port << 8) |
165cd8da8bbSVivien Didelot 				 (res << 5) | reg);
166cd8da8bbSVivien Didelot 	if (err)
167ec561276SVivien Didelot 		return err;
168cd8da8bbSVivien Didelot 
169cd8da8bbSVivien Didelot 	return mv88e6xxx_g2_irl_wait(chip);
170cd8da8bbSVivien Didelot }
171cd8da8bbSVivien Didelot 
172cd8da8bbSVivien Didelot int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
173cd8da8bbSVivien Didelot {
174cd8da8bbSVivien Didelot 	return mv88e6xxx_g2_irl_op(chip, MV88E6352_G2_IRL_CMD_OP_INIT_ALL, port,
175cd8da8bbSVivien Didelot 				   0, 0);
176cd8da8bbSVivien Didelot }
177cd8da8bbSVivien Didelot 
178cd8da8bbSVivien Didelot int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
179cd8da8bbSVivien Didelot {
180cd8da8bbSVivien Didelot 	return mv88e6xxx_g2_irl_op(chip, MV88E6390_G2_IRL_CMD_OP_INIT_ALL, port,
181cd8da8bbSVivien Didelot 				   0, 0);
182ec561276SVivien Didelot }
183ec561276SVivien Didelot 
18417a1594eSVivien Didelot /* Offset 0x0B: Cross-chip Port VLAN (Addr) Register
18517a1594eSVivien Didelot  * Offset 0x0C: Cross-chip Port VLAN Data Register
18617a1594eSVivien Didelot  */
18717a1594eSVivien Didelot 
18817a1594eSVivien Didelot static int mv88e6xxx_g2_pvt_op_wait(struct mv88e6xxx_chip *chip)
18917a1594eSVivien Didelot {
19017a1594eSVivien Didelot 	return mv88e6xxx_g2_wait(chip, GLOBAL2_PVT_ADDR, GLOBAL2_PVT_ADDR_BUSY);
19117a1594eSVivien Didelot }
19217a1594eSVivien Didelot 
19317a1594eSVivien Didelot static int mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip *chip, int src_dev,
19417a1594eSVivien Didelot 			       int src_port, u16 op)
19517a1594eSVivien Didelot {
19617a1594eSVivien Didelot 	int err;
19717a1594eSVivien Didelot 
19817a1594eSVivien Didelot 	/* 9-bit Cross-chip PVT pointer: with GLOBAL2_MISC_5_BIT_PORT cleared,
19917a1594eSVivien Didelot 	 * source device is 5-bit, source port is 4-bit.
20017a1594eSVivien Didelot 	 */
20117a1594eSVivien Didelot 	op |= (src_dev & 0x1f) << 4;
20217a1594eSVivien Didelot 	op |= (src_port & 0xf);
20317a1594eSVivien Didelot 
20417a1594eSVivien Didelot 	err = mv88e6xxx_g2_write(chip, GLOBAL2_PVT_ADDR, op);
20517a1594eSVivien Didelot 	if (err)
20617a1594eSVivien Didelot 		return err;
20717a1594eSVivien Didelot 
20817a1594eSVivien Didelot 	return mv88e6xxx_g2_pvt_op_wait(chip);
20917a1594eSVivien Didelot }
21017a1594eSVivien Didelot 
21117a1594eSVivien Didelot int mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev,
21217a1594eSVivien Didelot 			   int src_port, u16 data)
21317a1594eSVivien Didelot {
21417a1594eSVivien Didelot 	int err;
21517a1594eSVivien Didelot 
21617a1594eSVivien Didelot 	err = mv88e6xxx_g2_pvt_op_wait(chip);
21717a1594eSVivien Didelot 	if (err)
21817a1594eSVivien Didelot 		return err;
21917a1594eSVivien Didelot 
22017a1594eSVivien Didelot 	err = mv88e6xxx_g2_write(chip, GLOBAL2_PVT_DATA, data);
22117a1594eSVivien Didelot 	if (err)
22217a1594eSVivien Didelot 		return err;
22317a1594eSVivien Didelot 
22417a1594eSVivien Didelot 	return mv88e6xxx_g2_pvt_op(chip, src_dev, src_port,
22517a1594eSVivien Didelot 				   GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN);
22617a1594eSVivien Didelot }
22717a1594eSVivien Didelot 
228ec561276SVivien Didelot /* Offset 0x0D: Switch MAC/WoL/WoF register */
229ec561276SVivien Didelot 
230ec561276SVivien Didelot static int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip,
231ec561276SVivien Didelot 					 unsigned int pointer, u8 data)
232ec561276SVivien Didelot {
233ec561276SVivien Didelot 	u16 val = (pointer << 8) | data;
234ec561276SVivien Didelot 
2359fe850fbSVivien Didelot 	return mv88e6xxx_g2_update(chip, GLOBAL2_SWITCH_MAC, val);
236ec561276SVivien Didelot }
237ec561276SVivien Didelot 
238ec561276SVivien Didelot int mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr)
239ec561276SVivien Didelot {
240ec561276SVivien Didelot 	int i, err;
241ec561276SVivien Didelot 
242ec561276SVivien Didelot 	for (i = 0; i < 6; i++) {
243ec561276SVivien Didelot 		err = mv88e6xxx_g2_switch_mac_write(chip, i, addr[i]);
244ec561276SVivien Didelot 		if (err)
245ec561276SVivien Didelot 			break;
246ec561276SVivien Didelot 	}
247ec561276SVivien Didelot 
248ec561276SVivien Didelot 	return err;
249ec561276SVivien Didelot }
250ec561276SVivien Didelot 
251ec561276SVivien Didelot /* Offset 0x0F: Priority Override Table */
252ec561276SVivien Didelot 
253ec561276SVivien Didelot static int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer,
254ec561276SVivien Didelot 				  u8 data)
255ec561276SVivien Didelot {
256ec561276SVivien Didelot 	u16 val = (pointer << 8) | (data & 0x7);
257ec561276SVivien Didelot 
2589fe850fbSVivien Didelot 	return mv88e6xxx_g2_update(chip, GLOBAL2_PRIO_OVERRIDE, val);
259ec561276SVivien Didelot }
260ec561276SVivien Didelot 
261ec561276SVivien Didelot static int mv88e6xxx_g2_clear_pot(struct mv88e6xxx_chip *chip)
262ec561276SVivien Didelot {
263ec561276SVivien Didelot 	int i, err;
264ec561276SVivien Didelot 
265ec561276SVivien Didelot 	/* Clear all sixteen possible Priority Override entries */
266ec561276SVivien Didelot 	for (i = 0; i < 16; i++) {
267ec561276SVivien Didelot 		err = mv88e6xxx_g2_pot_write(chip, i, 0);
268ec561276SVivien Didelot 		if (err)
269ec561276SVivien Didelot 			break;
270ec561276SVivien Didelot 	}
271ec561276SVivien Didelot 
272ec561276SVivien Didelot 	return err;
273ec561276SVivien Didelot }
274ec561276SVivien Didelot 
275ec561276SVivien Didelot /* Offset 0x14: EEPROM Command
27698fc3c6fSVivien Didelot  * Offset 0x15: EEPROM Data (for 16-bit data access)
27798fc3c6fSVivien Didelot  * Offset 0x15: EEPROM Addr (for 8-bit data access)
278ec561276SVivien Didelot  */
279ec561276SVivien Didelot 
280ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
281ec561276SVivien Didelot {
2829fe850fbSVivien Didelot 	return mv88e6xxx_g2_wait(chip, GLOBAL2_EEPROM_CMD,
283ec561276SVivien Didelot 				 GLOBAL2_EEPROM_CMD_BUSY |
284ec561276SVivien Didelot 				 GLOBAL2_EEPROM_CMD_RUNNING);
285ec561276SVivien Didelot }
286ec561276SVivien Didelot 
287ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
288ec561276SVivien Didelot {
289ec561276SVivien Didelot 	int err;
290ec561276SVivien Didelot 
2919fe850fbSVivien Didelot 	err = mv88e6xxx_g2_write(chip, GLOBAL2_EEPROM_CMD, cmd);
292ec561276SVivien Didelot 	if (err)
293ec561276SVivien Didelot 		return err;
294ec561276SVivien Didelot 
295ec561276SVivien Didelot 	return mv88e6xxx_g2_eeprom_wait(chip);
296ec561276SVivien Didelot }
297ec561276SVivien Didelot 
29898fc3c6fSVivien Didelot static int mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip *chip,
29998fc3c6fSVivien Didelot 				     u16 addr, u8 *data)
30098fc3c6fSVivien Didelot {
30198fc3c6fSVivien Didelot 	u16 cmd = GLOBAL2_EEPROM_CMD_OP_READ;
30298fc3c6fSVivien Didelot 	int err;
30398fc3c6fSVivien Didelot 
30498fc3c6fSVivien Didelot 	err = mv88e6xxx_g2_eeprom_wait(chip);
30598fc3c6fSVivien Didelot 	if (err)
30698fc3c6fSVivien Didelot 		return err;
30798fc3c6fSVivien Didelot 
30898fc3c6fSVivien Didelot 	err = mv88e6xxx_g2_write(chip, GLOBAL2_EEPROM_ADDR, addr);
30998fc3c6fSVivien Didelot 	if (err)
31098fc3c6fSVivien Didelot 		return err;
31198fc3c6fSVivien Didelot 
31298fc3c6fSVivien Didelot 	err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
31398fc3c6fSVivien Didelot 	if (err)
31498fc3c6fSVivien Didelot 		return err;
31598fc3c6fSVivien Didelot 
31698fc3c6fSVivien Didelot 	err = mv88e6xxx_g2_read(chip, GLOBAL2_EEPROM_CMD, &cmd);
31798fc3c6fSVivien Didelot 	if (err)
31898fc3c6fSVivien Didelot 		return err;
31998fc3c6fSVivien Didelot 
32098fc3c6fSVivien Didelot 	*data = cmd & 0xff;
32198fc3c6fSVivien Didelot 
32298fc3c6fSVivien Didelot 	return 0;
32398fc3c6fSVivien Didelot }
32498fc3c6fSVivien Didelot 
32598fc3c6fSVivien Didelot static int mv88e6xxx_g2_eeprom_write8(struct mv88e6xxx_chip *chip,
32698fc3c6fSVivien Didelot 				      u16 addr, u8 data)
32798fc3c6fSVivien Didelot {
32898fc3c6fSVivien Didelot 	u16 cmd = GLOBAL2_EEPROM_CMD_OP_WRITE | GLOBAL2_EEPROM_CMD_WRITE_EN;
32998fc3c6fSVivien Didelot 	int err;
33098fc3c6fSVivien Didelot 
33198fc3c6fSVivien Didelot 	err = mv88e6xxx_g2_eeprom_wait(chip);
33298fc3c6fSVivien Didelot 	if (err)
33398fc3c6fSVivien Didelot 		return err;
33498fc3c6fSVivien Didelot 
33598fc3c6fSVivien Didelot 	err = mv88e6xxx_g2_write(chip, GLOBAL2_EEPROM_ADDR, addr);
33698fc3c6fSVivien Didelot 	if (err)
33798fc3c6fSVivien Didelot 		return err;
33898fc3c6fSVivien Didelot 
33998fc3c6fSVivien Didelot 	return mv88e6xxx_g2_eeprom_cmd(chip, cmd | data);
34098fc3c6fSVivien Didelot }
34198fc3c6fSVivien Didelot 
342ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip,
343ec561276SVivien Didelot 				      u8 addr, u16 *data)
344ec561276SVivien Didelot {
345ec561276SVivien Didelot 	u16 cmd = GLOBAL2_EEPROM_CMD_OP_READ | addr;
346ec561276SVivien Didelot 	int err;
347ec561276SVivien Didelot 
348ec561276SVivien Didelot 	err = mv88e6xxx_g2_eeprom_wait(chip);
349ec561276SVivien Didelot 	if (err)
350ec561276SVivien Didelot 		return err;
351ec561276SVivien Didelot 
352ec561276SVivien Didelot 	err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
353ec561276SVivien Didelot 	if (err)
354ec561276SVivien Didelot 		return err;
355ec561276SVivien Didelot 
3569fe850fbSVivien Didelot 	return mv88e6xxx_g2_read(chip, GLOBAL2_EEPROM_DATA, data);
357ec561276SVivien Didelot }
358ec561276SVivien Didelot 
359ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip *chip,
360ec561276SVivien Didelot 				       u8 addr, u16 data)
361ec561276SVivien Didelot {
362ec561276SVivien Didelot 	u16 cmd = GLOBAL2_EEPROM_CMD_OP_WRITE | addr;
363ec561276SVivien Didelot 	int err;
364ec561276SVivien Didelot 
365ec561276SVivien Didelot 	err = mv88e6xxx_g2_eeprom_wait(chip);
366ec561276SVivien Didelot 	if (err)
367ec561276SVivien Didelot 		return err;
368ec561276SVivien Didelot 
3699fe850fbSVivien Didelot 	err = mv88e6xxx_g2_write(chip, GLOBAL2_EEPROM_DATA, data);
370ec561276SVivien Didelot 	if (err)
371ec561276SVivien Didelot 		return err;
372ec561276SVivien Didelot 
373ec561276SVivien Didelot 	return mv88e6xxx_g2_eeprom_cmd(chip, cmd);
374ec561276SVivien Didelot }
375ec561276SVivien Didelot 
37698fc3c6fSVivien Didelot int mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip *chip,
37798fc3c6fSVivien Didelot 			     struct ethtool_eeprom *eeprom, u8 *data)
37898fc3c6fSVivien Didelot {
37998fc3c6fSVivien Didelot 	unsigned int offset = eeprom->offset;
38098fc3c6fSVivien Didelot 	unsigned int len = eeprom->len;
38198fc3c6fSVivien Didelot 	int err;
38298fc3c6fSVivien Didelot 
38398fc3c6fSVivien Didelot 	eeprom->len = 0;
38498fc3c6fSVivien Didelot 
38598fc3c6fSVivien Didelot 	while (len) {
38698fc3c6fSVivien Didelot 		err = mv88e6xxx_g2_eeprom_read8(chip, offset, data);
38798fc3c6fSVivien Didelot 		if (err)
38898fc3c6fSVivien Didelot 			return err;
38998fc3c6fSVivien Didelot 
39098fc3c6fSVivien Didelot 		eeprom->len++;
39198fc3c6fSVivien Didelot 		offset++;
39298fc3c6fSVivien Didelot 		data++;
39398fc3c6fSVivien Didelot 		len--;
39498fc3c6fSVivien Didelot 	}
39598fc3c6fSVivien Didelot 
39698fc3c6fSVivien Didelot 	return 0;
39798fc3c6fSVivien Didelot }
39898fc3c6fSVivien Didelot 
39998fc3c6fSVivien Didelot int mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip *chip,
40098fc3c6fSVivien Didelot 			     struct ethtool_eeprom *eeprom, u8 *data)
40198fc3c6fSVivien Didelot {
40298fc3c6fSVivien Didelot 	unsigned int offset = eeprom->offset;
40398fc3c6fSVivien Didelot 	unsigned int len = eeprom->len;
40498fc3c6fSVivien Didelot 	int err;
40598fc3c6fSVivien Didelot 
40698fc3c6fSVivien Didelot 	eeprom->len = 0;
40798fc3c6fSVivien Didelot 
40898fc3c6fSVivien Didelot 	while (len) {
40998fc3c6fSVivien Didelot 		err = mv88e6xxx_g2_eeprom_write8(chip, offset, *data);
41098fc3c6fSVivien Didelot 		if (err)
41198fc3c6fSVivien Didelot 			return err;
41298fc3c6fSVivien Didelot 
41398fc3c6fSVivien Didelot 		eeprom->len++;
41498fc3c6fSVivien Didelot 		offset++;
41598fc3c6fSVivien Didelot 		data++;
41698fc3c6fSVivien Didelot 		len--;
41798fc3c6fSVivien Didelot 	}
41898fc3c6fSVivien Didelot 
41998fc3c6fSVivien Didelot 	return 0;
42098fc3c6fSVivien Didelot }
42198fc3c6fSVivien Didelot 
422ec561276SVivien Didelot int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
423ec561276SVivien Didelot 			      struct ethtool_eeprom *eeprom, u8 *data)
424ec561276SVivien Didelot {
425ec561276SVivien Didelot 	unsigned int offset = eeprom->offset;
426ec561276SVivien Didelot 	unsigned int len = eeprom->len;
427ec561276SVivien Didelot 	u16 val;
428ec561276SVivien Didelot 	int err;
429ec561276SVivien Didelot 
430ec561276SVivien Didelot 	eeprom->len = 0;
431ec561276SVivien Didelot 
432ec561276SVivien Didelot 	if (offset & 1) {
433ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
434ec561276SVivien Didelot 		if (err)
435ec561276SVivien Didelot 			return err;
436ec561276SVivien Didelot 
437ec561276SVivien Didelot 		*data++ = (val >> 8) & 0xff;
438ec561276SVivien Didelot 
439ec561276SVivien Didelot 		offset++;
440ec561276SVivien Didelot 		len--;
441ec561276SVivien Didelot 		eeprom->len++;
442ec561276SVivien Didelot 	}
443ec561276SVivien Didelot 
444ec561276SVivien Didelot 	while (len >= 2) {
445ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
446ec561276SVivien Didelot 		if (err)
447ec561276SVivien Didelot 			return err;
448ec561276SVivien Didelot 
449ec561276SVivien Didelot 		*data++ = val & 0xff;
450ec561276SVivien Didelot 		*data++ = (val >> 8) & 0xff;
451ec561276SVivien Didelot 
452ec561276SVivien Didelot 		offset += 2;
453ec561276SVivien Didelot 		len -= 2;
454ec561276SVivien Didelot 		eeprom->len += 2;
455ec561276SVivien Didelot 	}
456ec561276SVivien Didelot 
457ec561276SVivien Didelot 	if (len) {
458ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
459ec561276SVivien Didelot 		if (err)
460ec561276SVivien Didelot 			return err;
461ec561276SVivien Didelot 
462ec561276SVivien Didelot 		*data++ = val & 0xff;
463ec561276SVivien Didelot 
464ec561276SVivien Didelot 		offset++;
465ec561276SVivien Didelot 		len--;
466ec561276SVivien Didelot 		eeprom->len++;
467ec561276SVivien Didelot 	}
468ec561276SVivien Didelot 
469ec561276SVivien Didelot 	return 0;
470ec561276SVivien Didelot }
471ec561276SVivien Didelot 
472ec561276SVivien Didelot int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
473ec561276SVivien Didelot 			      struct ethtool_eeprom *eeprom, u8 *data)
474ec561276SVivien Didelot {
475ec561276SVivien Didelot 	unsigned int offset = eeprom->offset;
476ec561276SVivien Didelot 	unsigned int len = eeprom->len;
477ec561276SVivien Didelot 	u16 val;
478ec561276SVivien Didelot 	int err;
479ec561276SVivien Didelot 
480ec561276SVivien Didelot 	/* Ensure the RO WriteEn bit is set */
4819fe850fbSVivien Didelot 	err = mv88e6xxx_g2_read(chip, GLOBAL2_EEPROM_CMD, &val);
482ec561276SVivien Didelot 	if (err)
483ec561276SVivien Didelot 		return err;
484ec561276SVivien Didelot 
485ec561276SVivien Didelot 	if (!(val & GLOBAL2_EEPROM_CMD_WRITE_EN))
486ec561276SVivien Didelot 		return -EROFS;
487ec561276SVivien Didelot 
488ec561276SVivien Didelot 	eeprom->len = 0;
489ec561276SVivien Didelot 
490ec561276SVivien Didelot 	if (offset & 1) {
491ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
492ec561276SVivien Didelot 		if (err)
493ec561276SVivien Didelot 			return err;
494ec561276SVivien Didelot 
495ec561276SVivien Didelot 		val = (*data++ << 8) | (val & 0xff);
496ec561276SVivien Didelot 
497ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
498ec561276SVivien Didelot 		if (err)
499ec561276SVivien Didelot 			return err;
500ec561276SVivien Didelot 
501ec561276SVivien Didelot 		offset++;
502ec561276SVivien Didelot 		len--;
503ec561276SVivien Didelot 		eeprom->len++;
504ec561276SVivien Didelot 	}
505ec561276SVivien Didelot 
506ec561276SVivien Didelot 	while (len >= 2) {
507ec561276SVivien Didelot 		val = *data++;
508ec561276SVivien Didelot 		val |= *data++ << 8;
509ec561276SVivien Didelot 
510ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
511ec561276SVivien Didelot 		if (err)
512ec561276SVivien Didelot 			return err;
513ec561276SVivien Didelot 
514ec561276SVivien Didelot 		offset += 2;
515ec561276SVivien Didelot 		len -= 2;
516ec561276SVivien Didelot 		eeprom->len += 2;
517ec561276SVivien Didelot 	}
518ec561276SVivien Didelot 
519ec561276SVivien Didelot 	if (len) {
520ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
521ec561276SVivien Didelot 		if (err)
522ec561276SVivien Didelot 			return err;
523ec561276SVivien Didelot 
524ec561276SVivien Didelot 		val = (val & 0xff00) | *data++;
525ec561276SVivien Didelot 
526ec561276SVivien Didelot 		err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
527ec561276SVivien Didelot 		if (err)
528ec561276SVivien Didelot 			return err;
529ec561276SVivien Didelot 
530ec561276SVivien Didelot 		offset++;
531ec561276SVivien Didelot 		len--;
532ec561276SVivien Didelot 		eeprom->len++;
533ec561276SVivien Didelot 	}
534ec561276SVivien Didelot 
535ec561276SVivien Didelot 	return 0;
536ec561276SVivien Didelot }
537ec561276SVivien Didelot 
538ec561276SVivien Didelot /* Offset 0x18: SMI PHY Command Register
539ec561276SVivien Didelot  * Offset 0x19: SMI PHY Data Register
540ec561276SVivien Didelot  */
541ec561276SVivien Didelot 
542ec561276SVivien Didelot static int mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip *chip)
543ec561276SVivien Didelot {
544e289ef0dSVivien Didelot 	return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_SMI_PHY_CMD,
545e289ef0dSVivien Didelot 				 MV88E6XXX_G2_SMI_PHY_CMD_BUSY);
546ec561276SVivien Didelot }
547ec561276SVivien Didelot 
548ec561276SVivien Didelot static int mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
549ec561276SVivien Didelot {
550ec561276SVivien Didelot 	int err;
551ec561276SVivien Didelot 
552e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_CMD,
553e289ef0dSVivien Didelot 				 MV88E6XXX_G2_SMI_PHY_CMD_BUSY | cmd);
554ec561276SVivien Didelot 	if (err)
555ec561276SVivien Didelot 		return err;
556ec561276SVivien Didelot 
557ec561276SVivien Didelot 	return mv88e6xxx_g2_smi_phy_wait(chip);
558ec561276SVivien Didelot }
559ec561276SVivien Didelot 
560e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_access(struct mv88e6xxx_chip *chip,
561e289ef0dSVivien Didelot 				       bool external, bool c45, u16 op, int dev,
562e289ef0dSVivien Didelot 				       int reg)
563ec561276SVivien Didelot {
564e289ef0dSVivien Didelot 	u16 cmd = op;
565ec561276SVivien Didelot 
566cf3e80dfSAndrew Lunn 	if (external)
567e289ef0dSVivien Didelot 		cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_EXTERNAL;
568e289ef0dSVivien Didelot 	else
569e289ef0dSVivien Didelot 		cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_INTERNAL; /* empty mask */
570cf3e80dfSAndrew Lunn 
571e289ef0dSVivien Didelot 	if (c45)
572e289ef0dSVivien Didelot 		cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_45; /* empty mask */
573e289ef0dSVivien Didelot 	else
574e289ef0dSVivien Didelot 		cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_22;
575cf3e80dfSAndrew Lunn 
576e289ef0dSVivien Didelot 	dev <<= __bf_shf(MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK);
577e289ef0dSVivien Didelot 	cmd |= dev & MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK;
578e289ef0dSVivien Didelot 	cmd |= reg & MV88E6XXX_G2_SMI_PHY_CMD_REG_ADDR_MASK;
579cf3e80dfSAndrew Lunn 
580cf3e80dfSAndrew Lunn 	return mv88e6xxx_g2_smi_phy_cmd(chip, cmd);
581cf3e80dfSAndrew Lunn }
582cf3e80dfSAndrew Lunn 
583e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_access_c22(struct mv88e6xxx_chip *chip,
584e289ef0dSVivien Didelot 					   bool external, u16 op, int dev,
585e289ef0dSVivien Didelot 					   int reg)
586cf3e80dfSAndrew Lunn {
587e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_access(chip, external, false, op, dev, reg);
588cf3e80dfSAndrew Lunn }
589cf3e80dfSAndrew Lunn 
590e289ef0dSVivien Didelot /* IEEE 802.3 Clause 22 Read Data Register */
591e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_read_data_c22(struct mv88e6xxx_chip *chip,
592e289ef0dSVivien Didelot 					      bool external, int dev, int reg,
593e289ef0dSVivien Didelot 					      u16 *data)
594cf3e80dfSAndrew Lunn {
595e289ef0dSVivien Didelot 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_READ_DATA;
596cf3e80dfSAndrew Lunn 	int err;
597cf3e80dfSAndrew Lunn 
598ec561276SVivien Didelot 	err = mv88e6xxx_g2_smi_phy_wait(chip);
599ec561276SVivien Didelot 	if (err)
600ec561276SVivien Didelot 		return err;
601ec561276SVivien Didelot 
602e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
603ec561276SVivien Didelot 	if (err)
604ec561276SVivien Didelot 		return err;
605ec561276SVivien Didelot 
606e289ef0dSVivien Didelot 	return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
607ec561276SVivien Didelot }
608ec561276SVivien Didelot 
609e289ef0dSVivien Didelot /* IEEE 802.3 Clause 22 Write Data Register */
610e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_data_c22(struct mv88e6xxx_chip *chip,
611e289ef0dSVivien Didelot 					       bool external, int dev, int reg,
612e289ef0dSVivien Didelot 					       u16 data)
613e289ef0dSVivien Didelot {
614e289ef0dSVivien Didelot 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_WRITE_DATA;
615e289ef0dSVivien Didelot 	int err;
616e289ef0dSVivien Didelot 
617e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_smi_phy_wait(chip);
618e289ef0dSVivien Didelot 	if (err)
619e289ef0dSVivien Didelot 		return err;
620e289ef0dSVivien Didelot 
621e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
622e289ef0dSVivien Didelot 	if (err)
623e289ef0dSVivien Didelot 		return err;
624e289ef0dSVivien Didelot 
625e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
626e289ef0dSVivien Didelot }
627e289ef0dSVivien Didelot 
628e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_access_c45(struct mv88e6xxx_chip *chip,
629e289ef0dSVivien Didelot 					   bool external, u16 op, int port,
630e289ef0dSVivien Didelot 					   int dev)
631e289ef0dSVivien Didelot {
632e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_access(chip, external, true, op, port, dev);
633e289ef0dSVivien Didelot }
634e289ef0dSVivien Didelot 
635e289ef0dSVivien Didelot /* IEEE 802.3 Clause 45 Write Address Register */
636e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_addr_c45(struct mv88e6xxx_chip *chip,
637e289ef0dSVivien Didelot 					       bool external, int port, int dev,
638e289ef0dSVivien Didelot 					       int addr)
639e289ef0dSVivien Didelot {
640e289ef0dSVivien Didelot 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_ADDR;
641e289ef0dSVivien Didelot 	int err;
642e289ef0dSVivien Didelot 
643e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_smi_phy_wait(chip);
644e289ef0dSVivien Didelot 	if (err)
645e289ef0dSVivien Didelot 		return err;
646e289ef0dSVivien Didelot 
647e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, addr);
648e289ef0dSVivien Didelot 	if (err)
649e289ef0dSVivien Didelot 		return err;
650e289ef0dSVivien Didelot 
651e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
652e289ef0dSVivien Didelot }
653e289ef0dSVivien Didelot 
654e289ef0dSVivien Didelot /* IEEE 802.3 Clause 45 Read Data Register */
655e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_read_data_c45(struct mv88e6xxx_chip *chip,
656e289ef0dSVivien Didelot 					      bool external, int port, int dev,
657e289ef0dSVivien Didelot 					      u16 *data)
658e289ef0dSVivien Didelot {
659e289ef0dSVivien Didelot 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_READ_DATA;
660e289ef0dSVivien Didelot 	int err;
661e289ef0dSVivien Didelot 
662e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
663e289ef0dSVivien Didelot 	if (err)
664e289ef0dSVivien Didelot 		return err;
665e289ef0dSVivien Didelot 
666e289ef0dSVivien Didelot 	return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
667e289ef0dSVivien Didelot }
668e289ef0dSVivien Didelot 
669e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip,
670e289ef0dSVivien Didelot 					 bool external, int port, int reg,
671e289ef0dSVivien Didelot 					 u16 *data)
672e289ef0dSVivien Didelot {
673e289ef0dSVivien Didelot 	int dev = (reg >> 16) & 0x1f;
674e289ef0dSVivien Didelot 	int addr = reg & 0xffff;
675e289ef0dSVivien Didelot 	int err;
676e289ef0dSVivien Didelot 
677e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev,
678e289ef0dSVivien Didelot 						  addr);
679e289ef0dSVivien Didelot 	if (err)
680e289ef0dSVivien Didelot 		return err;
681e289ef0dSVivien Didelot 
682e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_read_data_c45(chip, external, port, dev,
683e289ef0dSVivien Didelot 						  data);
684e289ef0dSVivien Didelot }
685e289ef0dSVivien Didelot 
686e289ef0dSVivien Didelot /* IEEE 802.3 Clause 45 Write Data Register */
687e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_data_c45(struct mv88e6xxx_chip *chip,
688e289ef0dSVivien Didelot 					       bool external, int port, int dev,
689e289ef0dSVivien Didelot 					       u16 data)
690e289ef0dSVivien Didelot {
691e289ef0dSVivien Didelot 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_DATA;
692e289ef0dSVivien Didelot 	int err;
693e289ef0dSVivien Didelot 
694e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
695e289ef0dSVivien Didelot 	if (err)
696e289ef0dSVivien Didelot 		return err;
697e289ef0dSVivien Didelot 
698e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
699e289ef0dSVivien Didelot }
700e289ef0dSVivien Didelot 
701e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip,
702e289ef0dSVivien Didelot 					  bool external, int port, int reg,
703e289ef0dSVivien Didelot 					  u16 data)
704e289ef0dSVivien Didelot {
705e289ef0dSVivien Didelot 	int dev = (reg >> 16) & 0x1f;
706e289ef0dSVivien Didelot 	int addr = reg & 0xffff;
707e289ef0dSVivien Didelot 	int err;
708e289ef0dSVivien Didelot 
709e289ef0dSVivien Didelot 	err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev,
710e289ef0dSVivien Didelot 						  addr);
711e289ef0dSVivien Didelot 	if (err)
712e289ef0dSVivien Didelot 		return err;
713e289ef0dSVivien Didelot 
714e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_write_data_c45(chip, external, port, dev,
715e289ef0dSVivien Didelot 						   data);
716e289ef0dSVivien Didelot }
717e289ef0dSVivien Didelot 
718e289ef0dSVivien Didelot int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
719cf3e80dfSAndrew Lunn 			      int addr, int reg, u16 *val)
720cf3e80dfSAndrew Lunn {
721cf3e80dfSAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
722cf3e80dfSAndrew Lunn 	bool external = mdio_bus->external;
723cf3e80dfSAndrew Lunn 
724cf3e80dfSAndrew Lunn 	if (reg & MII_ADDR_C45)
725e289ef0dSVivien Didelot 		return mv88e6xxx_g2_smi_phy_read_c45(chip, external, addr, reg,
726e289ef0dSVivien Didelot 						     val);
727e289ef0dSVivien Didelot 
728e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_read_data_c22(chip, external, addr, reg,
729e289ef0dSVivien Didelot 						  val);
730cf3e80dfSAndrew Lunn }
731cf3e80dfSAndrew Lunn 
732e289ef0dSVivien Didelot int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
733cf3e80dfSAndrew Lunn 			       int addr, int reg, u16 val)
734cf3e80dfSAndrew Lunn {
735cf3e80dfSAndrew Lunn 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
736cf3e80dfSAndrew Lunn 	bool external = mdio_bus->external;
737cf3e80dfSAndrew Lunn 
738cf3e80dfSAndrew Lunn 	if (reg & MII_ADDR_C45)
739e289ef0dSVivien Didelot 		return mv88e6xxx_g2_smi_phy_write_c45(chip, external, addr, reg,
740e289ef0dSVivien Didelot 						      val);
741cf3e80dfSAndrew Lunn 
742e289ef0dSVivien Didelot 	return mv88e6xxx_g2_smi_phy_write_data_c22(chip, external, addr, reg,
743e289ef0dSVivien Didelot 						   val);
744cf3e80dfSAndrew Lunn }
745cf3e80dfSAndrew Lunn 
746fcd25166SAndrew Lunn static int mv88e6097_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
747fcd25166SAndrew Lunn {
748fcd25166SAndrew Lunn 	u16 reg;
749fcd25166SAndrew Lunn 
750fcd25166SAndrew Lunn 	mv88e6xxx_g2_read(chip, GLOBAL2_WDOG_CONTROL, &reg);
751fcd25166SAndrew Lunn 
752fcd25166SAndrew Lunn 	dev_info(chip->dev, "Watchdog event: 0x%04x", reg);
753fcd25166SAndrew Lunn 
754fcd25166SAndrew Lunn 	return IRQ_HANDLED;
755fcd25166SAndrew Lunn }
756fcd25166SAndrew Lunn 
757fcd25166SAndrew Lunn static void mv88e6097_watchdog_free(struct mv88e6xxx_chip *chip)
758fcd25166SAndrew Lunn {
759fcd25166SAndrew Lunn 	u16 reg;
760fcd25166SAndrew Lunn 
761fcd25166SAndrew Lunn 	mv88e6xxx_g2_read(chip, GLOBAL2_WDOG_CONTROL, &reg);
762fcd25166SAndrew Lunn 
763fcd25166SAndrew Lunn 	reg &= ~(GLOBAL2_WDOG_CONTROL_EGRESS_ENABLE |
764fcd25166SAndrew Lunn 		 GLOBAL2_WDOG_CONTROL_QC_ENABLE);
765fcd25166SAndrew Lunn 
766fcd25166SAndrew Lunn 	mv88e6xxx_g2_write(chip, GLOBAL2_WDOG_CONTROL, reg);
767fcd25166SAndrew Lunn }
768fcd25166SAndrew Lunn 
769fcd25166SAndrew Lunn static int mv88e6097_watchdog_setup(struct mv88e6xxx_chip *chip)
770fcd25166SAndrew Lunn {
771fcd25166SAndrew Lunn 	return mv88e6xxx_g2_write(chip, GLOBAL2_WDOG_CONTROL,
772fcd25166SAndrew Lunn 				  GLOBAL2_WDOG_CONTROL_EGRESS_ENABLE |
773fcd25166SAndrew Lunn 				  GLOBAL2_WDOG_CONTROL_QC_ENABLE |
774fcd25166SAndrew Lunn 				  GLOBAL2_WDOG_CONTROL_SWRESET);
775fcd25166SAndrew Lunn }
776fcd25166SAndrew Lunn 
777fcd25166SAndrew Lunn const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {
778fcd25166SAndrew Lunn 	.irq_action = mv88e6097_watchdog_action,
779fcd25166SAndrew Lunn 	.irq_setup = mv88e6097_watchdog_setup,
780fcd25166SAndrew Lunn 	.irq_free = mv88e6097_watchdog_free,
781fcd25166SAndrew Lunn };
782fcd25166SAndrew Lunn 
78361303736SAndrew Lunn static int mv88e6390_watchdog_setup(struct mv88e6xxx_chip *chip)
78461303736SAndrew Lunn {
78561303736SAndrew Lunn 	return mv88e6xxx_g2_update(chip, GLOBAL2_WDOG_CONTROL,
78661303736SAndrew Lunn 				   GLOBAL2_WDOG_INT_ENABLE |
78761303736SAndrew Lunn 				   GLOBAL2_WDOG_CUT_THROUGH |
78861303736SAndrew Lunn 				   GLOBAL2_WDOG_QUEUE_CONTROLLER |
78961303736SAndrew Lunn 				   GLOBAL2_WDOG_EGRESS |
79061303736SAndrew Lunn 				   GLOBAL2_WDOG_FORCE_IRQ);
79161303736SAndrew Lunn }
79261303736SAndrew Lunn 
79361303736SAndrew Lunn static int mv88e6390_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
79461303736SAndrew Lunn {
79561303736SAndrew Lunn 	int err;
79661303736SAndrew Lunn 	u16 reg;
79761303736SAndrew Lunn 
79861303736SAndrew Lunn 	mv88e6xxx_g2_write(chip, GLOBAL2_WDOG_CONTROL, GLOBAL2_WDOG_EVENT);
79961303736SAndrew Lunn 	err = mv88e6xxx_g2_read(chip, GLOBAL2_WDOG_CONTROL, &reg);
80061303736SAndrew Lunn 
80161303736SAndrew Lunn 	dev_info(chip->dev, "Watchdog event: 0x%04x",
80261303736SAndrew Lunn 		 reg & GLOBAL2_WDOG_DATA_MASK);
80361303736SAndrew Lunn 
80461303736SAndrew Lunn 	mv88e6xxx_g2_write(chip, GLOBAL2_WDOG_CONTROL, GLOBAL2_WDOG_HISTORY);
80561303736SAndrew Lunn 	err = mv88e6xxx_g2_read(chip, GLOBAL2_WDOG_CONTROL, &reg);
80661303736SAndrew Lunn 
80761303736SAndrew Lunn 	dev_info(chip->dev, "Watchdog history: 0x%04x",
80861303736SAndrew Lunn 		 reg & GLOBAL2_WDOG_DATA_MASK);
80961303736SAndrew Lunn 
81061303736SAndrew Lunn 	/* Trigger a software reset to try to recover the switch */
81161303736SAndrew Lunn 	if (chip->info->ops->reset)
81261303736SAndrew Lunn 		chip->info->ops->reset(chip);
81361303736SAndrew Lunn 
81461303736SAndrew Lunn 	mv88e6390_watchdog_setup(chip);
81561303736SAndrew Lunn 
81661303736SAndrew Lunn 	return IRQ_HANDLED;
81761303736SAndrew Lunn }
81861303736SAndrew Lunn 
81961303736SAndrew Lunn static void mv88e6390_watchdog_free(struct mv88e6xxx_chip *chip)
82061303736SAndrew Lunn {
82161303736SAndrew Lunn 	mv88e6xxx_g2_update(chip, GLOBAL2_WDOG_CONTROL,
82261303736SAndrew Lunn 			    GLOBAL2_WDOG_INT_ENABLE);
82361303736SAndrew Lunn }
82461303736SAndrew Lunn 
82561303736SAndrew Lunn const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {
82661303736SAndrew Lunn 	.irq_action = mv88e6390_watchdog_action,
82761303736SAndrew Lunn 	.irq_setup = mv88e6390_watchdog_setup,
82861303736SAndrew Lunn 	.irq_free = mv88e6390_watchdog_free,
82961303736SAndrew Lunn };
83061303736SAndrew Lunn 
831fcd25166SAndrew Lunn static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id)
832fcd25166SAndrew Lunn {
833fcd25166SAndrew Lunn 	struct mv88e6xxx_chip *chip = dev_id;
834fcd25166SAndrew Lunn 	irqreturn_t ret = IRQ_NONE;
835fcd25166SAndrew Lunn 
836fcd25166SAndrew Lunn 	mutex_lock(&chip->reg_lock);
837fcd25166SAndrew Lunn 	if (chip->info->ops->watchdog_ops->irq_action)
838fcd25166SAndrew Lunn 		ret = chip->info->ops->watchdog_ops->irq_action(chip, irq);
839fcd25166SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
840fcd25166SAndrew Lunn 
841fcd25166SAndrew Lunn 	return ret;
842fcd25166SAndrew Lunn }
843fcd25166SAndrew Lunn 
844fcd25166SAndrew Lunn static void mv88e6xxx_g2_watchdog_free(struct mv88e6xxx_chip *chip)
845fcd25166SAndrew Lunn {
846fcd25166SAndrew Lunn 	mutex_lock(&chip->reg_lock);
847fcd25166SAndrew Lunn 	if (chip->info->ops->watchdog_ops->irq_free)
848fcd25166SAndrew Lunn 		chip->info->ops->watchdog_ops->irq_free(chip);
849fcd25166SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
850fcd25166SAndrew Lunn 
851fcd25166SAndrew Lunn 	free_irq(chip->watchdog_irq, chip);
852fcd25166SAndrew Lunn 	irq_dispose_mapping(chip->watchdog_irq);
853fcd25166SAndrew Lunn }
854fcd25166SAndrew Lunn 
855fcd25166SAndrew Lunn static int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip)
856fcd25166SAndrew Lunn {
857fcd25166SAndrew Lunn 	int err;
858fcd25166SAndrew Lunn 
859fcd25166SAndrew Lunn 	chip->watchdog_irq = irq_find_mapping(chip->g2_irq.domain,
860fcd25166SAndrew Lunn 					      GLOBAL2_INT_SOURCE_WATCHDOG);
861fcd25166SAndrew Lunn 	if (chip->watchdog_irq < 0)
862fcd25166SAndrew Lunn 		return chip->watchdog_irq;
863fcd25166SAndrew Lunn 
864fcd25166SAndrew Lunn 	err = request_threaded_irq(chip->watchdog_irq, NULL,
865fcd25166SAndrew Lunn 				   mv88e6xxx_g2_watchdog_thread_fn,
866fcd25166SAndrew Lunn 				   IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
867fcd25166SAndrew Lunn 				   "mv88e6xxx-watchdog", chip);
868fcd25166SAndrew Lunn 	if (err)
869fcd25166SAndrew Lunn 		return err;
870fcd25166SAndrew Lunn 
871fcd25166SAndrew Lunn 	mutex_lock(&chip->reg_lock);
872fcd25166SAndrew Lunn 	if (chip->info->ops->watchdog_ops->irq_setup)
873fcd25166SAndrew Lunn 		err = chip->info->ops->watchdog_ops->irq_setup(chip);
874fcd25166SAndrew Lunn 	mutex_unlock(&chip->reg_lock);
875fcd25166SAndrew Lunn 
876fcd25166SAndrew Lunn 	return err;
877fcd25166SAndrew Lunn }
878fcd25166SAndrew Lunn 
87981228996SVivien Didelot /* Offset 0x1D: Misc Register */
88081228996SVivien Didelot 
88181228996SVivien Didelot static int mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip *chip,
88281228996SVivien Didelot 					bool port_5_bit)
88381228996SVivien Didelot {
88481228996SVivien Didelot 	u16 val;
88581228996SVivien Didelot 	int err;
88681228996SVivien Didelot 
88781228996SVivien Didelot 	err = mv88e6xxx_g2_read(chip, GLOBAL2_MISC, &val);
88881228996SVivien Didelot 	if (err)
88981228996SVivien Didelot 		return err;
89081228996SVivien Didelot 
89181228996SVivien Didelot 	if (port_5_bit)
89281228996SVivien Didelot 		val |= GLOBAL2_MISC_5_BIT_PORT;
89381228996SVivien Didelot 	else
89481228996SVivien Didelot 		val &= ~GLOBAL2_MISC_5_BIT_PORT;
89581228996SVivien Didelot 
89681228996SVivien Didelot 	return mv88e6xxx_g2_write(chip, GLOBAL2_MISC, val);
89781228996SVivien Didelot }
89881228996SVivien Didelot 
89981228996SVivien Didelot int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip)
90081228996SVivien Didelot {
90181228996SVivien Didelot 	return mv88e6xxx_g2_misc_5_bit_port(chip, false);
90281228996SVivien Didelot }
90381228996SVivien Didelot 
904dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_mask(struct irq_data *d)
905dc30c35bSAndrew Lunn {
906dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
907dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
908dc30c35bSAndrew Lunn 
909dc30c35bSAndrew Lunn 	chip->g2_irq.masked |= (1 << n);
910dc30c35bSAndrew Lunn }
911dc30c35bSAndrew Lunn 
912dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_unmask(struct irq_data *d)
913dc30c35bSAndrew Lunn {
914dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
915dc30c35bSAndrew Lunn 	unsigned int n = d->hwirq;
916dc30c35bSAndrew Lunn 
917dc30c35bSAndrew Lunn 	chip->g2_irq.masked &= ~(1 << n);
918dc30c35bSAndrew Lunn }
919dc30c35bSAndrew Lunn 
920dc30c35bSAndrew Lunn static irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id)
921dc30c35bSAndrew Lunn {
922dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = dev_id;
923dc30c35bSAndrew Lunn 	unsigned int nhandled = 0;
924dc30c35bSAndrew Lunn 	unsigned int sub_irq;
925dc30c35bSAndrew Lunn 	unsigned int n;
926dc30c35bSAndrew Lunn 	int err;
927dc30c35bSAndrew Lunn 	u16 reg;
928dc30c35bSAndrew Lunn 
929dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
930dc30c35bSAndrew Lunn 	err = mv88e6xxx_g2_read(chip, GLOBAL2_INT_SOURCE, &reg);
931dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
932dc30c35bSAndrew Lunn 	if (err)
933dc30c35bSAndrew Lunn 		goto out;
934dc30c35bSAndrew Lunn 
935dc30c35bSAndrew Lunn 	for (n = 0; n < 16; ++n) {
936dc30c35bSAndrew Lunn 		if (reg & (1 << n)) {
937dc30c35bSAndrew Lunn 			sub_irq = irq_find_mapping(chip->g2_irq.domain, n);
938dc30c35bSAndrew Lunn 			handle_nested_irq(sub_irq);
939dc30c35bSAndrew Lunn 			++nhandled;
940dc30c35bSAndrew Lunn 		}
941dc30c35bSAndrew Lunn 	}
942dc30c35bSAndrew Lunn out:
943dc30c35bSAndrew Lunn 	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
944dc30c35bSAndrew Lunn }
945dc30c35bSAndrew Lunn 
946dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_bus_lock(struct irq_data *d)
947dc30c35bSAndrew Lunn {
948dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
949dc30c35bSAndrew Lunn 
950dc30c35bSAndrew Lunn 	mutex_lock(&chip->reg_lock);
951dc30c35bSAndrew Lunn }
952dc30c35bSAndrew Lunn 
953dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d)
954dc30c35bSAndrew Lunn {
955dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
956dc30c35bSAndrew Lunn 
957dc30c35bSAndrew Lunn 	mv88e6xxx_g2_write(chip, GLOBAL2_INT_MASK, ~chip->g2_irq.masked);
958dc30c35bSAndrew Lunn 
959dc30c35bSAndrew Lunn 	mutex_unlock(&chip->reg_lock);
960dc30c35bSAndrew Lunn }
961dc30c35bSAndrew Lunn 
962dc30c35bSAndrew Lunn static struct irq_chip mv88e6xxx_g2_irq_chip = {
963dc30c35bSAndrew Lunn 	.name			= "mv88e6xxx-g2",
964dc30c35bSAndrew Lunn 	.irq_mask		= mv88e6xxx_g2_irq_mask,
965dc30c35bSAndrew Lunn 	.irq_unmask		= mv88e6xxx_g2_irq_unmask,
966dc30c35bSAndrew Lunn 	.irq_bus_lock		= mv88e6xxx_g2_irq_bus_lock,
967dc30c35bSAndrew Lunn 	.irq_bus_sync_unlock	= mv88e6xxx_g2_irq_bus_sync_unlock,
968dc30c35bSAndrew Lunn };
969dc30c35bSAndrew Lunn 
970dc30c35bSAndrew Lunn static int mv88e6xxx_g2_irq_domain_map(struct irq_domain *d,
971dc30c35bSAndrew Lunn 				       unsigned int irq,
972dc30c35bSAndrew Lunn 				       irq_hw_number_t hwirq)
973dc30c35bSAndrew Lunn {
974dc30c35bSAndrew Lunn 	struct mv88e6xxx_chip *chip = d->host_data;
975dc30c35bSAndrew Lunn 
976dc30c35bSAndrew Lunn 	irq_set_chip_data(irq, d->host_data);
977dc30c35bSAndrew Lunn 	irq_set_chip_and_handler(irq, &chip->g2_irq.chip, handle_level_irq);
978dc30c35bSAndrew Lunn 	irq_set_noprobe(irq);
979dc30c35bSAndrew Lunn 
980dc30c35bSAndrew Lunn 	return 0;
981dc30c35bSAndrew Lunn }
982dc30c35bSAndrew Lunn 
983dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g2_irq_domain_ops = {
984dc30c35bSAndrew Lunn 	.map	= mv88e6xxx_g2_irq_domain_map,
985dc30c35bSAndrew Lunn 	.xlate	= irq_domain_xlate_twocell,
986dc30c35bSAndrew Lunn };
987dc30c35bSAndrew Lunn 
988dc30c35bSAndrew Lunn void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip)
989dc30c35bSAndrew Lunn {
990dc30c35bSAndrew Lunn 	int irq, virq;
991dc30c35bSAndrew Lunn 
992fcd25166SAndrew Lunn 	mv88e6xxx_g2_watchdog_free(chip);
993fcd25166SAndrew Lunn 
9948e757ebaSAndrew Lunn 	free_irq(chip->device_irq, chip);
9958e757ebaSAndrew Lunn 	irq_dispose_mapping(chip->device_irq);
9968e757ebaSAndrew Lunn 
997dc30c35bSAndrew Lunn 	for (irq = 0; irq < 16; irq++) {
998dc30c35bSAndrew Lunn 		virq = irq_find_mapping(chip->g2_irq.domain, irq);
999dc30c35bSAndrew Lunn 		irq_dispose_mapping(virq);
1000dc30c35bSAndrew Lunn 	}
1001dc30c35bSAndrew Lunn 
1002dc30c35bSAndrew Lunn 	irq_domain_remove(chip->g2_irq.domain);
1003dc30c35bSAndrew Lunn }
1004dc30c35bSAndrew Lunn 
1005dc30c35bSAndrew Lunn int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip)
1006dc30c35bSAndrew Lunn {
10078e757ebaSAndrew Lunn 	int err, irq, virq;
1008dc30c35bSAndrew Lunn 
1009dc30c35bSAndrew Lunn 	if (!chip->dev->of_node)
1010dc30c35bSAndrew Lunn 		return -EINVAL;
1011dc30c35bSAndrew Lunn 
1012dc30c35bSAndrew Lunn 	chip->g2_irq.domain = irq_domain_add_simple(
1013dc30c35bSAndrew Lunn 		chip->dev->of_node, 16, 0, &mv88e6xxx_g2_irq_domain_ops, chip);
1014dc30c35bSAndrew Lunn 	if (!chip->g2_irq.domain)
1015dc30c35bSAndrew Lunn 		return -ENOMEM;
1016dc30c35bSAndrew Lunn 
1017dc30c35bSAndrew Lunn 	for (irq = 0; irq < 16; irq++)
1018dc30c35bSAndrew Lunn 		irq_create_mapping(chip->g2_irq.domain, irq);
1019dc30c35bSAndrew Lunn 
1020dc30c35bSAndrew Lunn 	chip->g2_irq.chip = mv88e6xxx_g2_irq_chip;
1021dc30c35bSAndrew Lunn 	chip->g2_irq.masked = ~0;
1022dc30c35bSAndrew Lunn 
10238e757ebaSAndrew Lunn 	chip->device_irq = irq_find_mapping(chip->g1_irq.domain,
102482466921SVivien Didelot 					    MV88E6XXX_G1_STS_IRQ_DEVICE);
10258e757ebaSAndrew Lunn 	if (chip->device_irq < 0) {
10268e757ebaSAndrew Lunn 		err = chip->device_irq;
1027dc30c35bSAndrew Lunn 		goto out;
1028dc30c35bSAndrew Lunn 	}
1029dc30c35bSAndrew Lunn 
10308e757ebaSAndrew Lunn 	err = request_threaded_irq(chip->device_irq, NULL,
1031dc30c35bSAndrew Lunn 				   mv88e6xxx_g2_irq_thread_fn,
1032dc30c35bSAndrew Lunn 				   IRQF_ONESHOT, "mv88e6xxx-g1", chip);
1033dc30c35bSAndrew Lunn 	if (err)
1034dc30c35bSAndrew Lunn 		goto out;
1035dc30c35bSAndrew Lunn 
1036fcd25166SAndrew Lunn 	return mv88e6xxx_g2_watchdog_setup(chip);
10378e757ebaSAndrew Lunn 
1038dc30c35bSAndrew Lunn out:
10398e757ebaSAndrew Lunn 	for (irq = 0; irq < 16; irq++) {
10408e757ebaSAndrew Lunn 		virq = irq_find_mapping(chip->g2_irq.domain, irq);
10418e757ebaSAndrew Lunn 		irq_dispose_mapping(virq);
10428e757ebaSAndrew Lunn 	}
10438e757ebaSAndrew Lunn 
10448e757ebaSAndrew Lunn 	irq_domain_remove(chip->g2_irq.domain);
1045dc30c35bSAndrew Lunn 
1046dc30c35bSAndrew Lunn 	return err;
1047dc30c35bSAndrew Lunn }
1048dc30c35bSAndrew Lunn 
1049ec561276SVivien Didelot int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip)
1050ec561276SVivien Didelot {
1051ec561276SVivien Didelot 	u16 reg;
1052ec561276SVivien Didelot 	int err;
1053ec561276SVivien Didelot 
1054ec561276SVivien Didelot 	/* Ignore removed tag data on doubly tagged packets, disable
1055ec561276SVivien Didelot 	 * flow control messages, force flow control priority to the
1056ec561276SVivien Didelot 	 * highest, and send all special multicast frames to the CPU
1057ec561276SVivien Didelot 	 * port at the highest priority.
1058ec561276SVivien Didelot 	 */
1059ec561276SVivien Didelot 	reg = GLOBAL2_SWITCH_MGMT_FORCE_FLOW_CTRL_PRI | (0x7 << 4);
1060ec561276SVivien Didelot 	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_0X) ||
1061ec561276SVivien Didelot 	    mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_MGMT_EN_2X))
1062ec561276SVivien Didelot 		reg |= GLOBAL2_SWITCH_MGMT_RSVD2CPU | 0x7;
10639fe850fbSVivien Didelot 	err = mv88e6xxx_g2_write(chip, GLOBAL2_SWITCH_MGMT, reg);
1064ec561276SVivien Didelot 	if (err)
1065ec561276SVivien Didelot 		return err;
1066ec561276SVivien Didelot 
1067ec561276SVivien Didelot 	/* Program the DSA routing table. */
1068ec561276SVivien Didelot 	err = mv88e6xxx_g2_set_device_mapping(chip);
1069ec561276SVivien Didelot 	if (err)
1070ec561276SVivien Didelot 		return err;
1071ec561276SVivien Didelot 
1072ec561276SVivien Didelot 	/* Clear all trunk masks and mapping. */
1073ec561276SVivien Didelot 	err = mv88e6xxx_g2_clear_trunk(chip);
1074ec561276SVivien Didelot 	if (err)
1075ec561276SVivien Didelot 		return err;
1076ec561276SVivien Didelot 
1077ec561276SVivien Didelot 	if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_POT)) {
1078ec561276SVivien Didelot 		/* Clear the priority override table. */
1079ec561276SVivien Didelot 		err = mv88e6xxx_g2_clear_pot(chip);
1080ec561276SVivien Didelot 		if (err)
1081ec561276SVivien Didelot 			return err;
1082ec561276SVivien Didelot 	}
1083ec561276SVivien Didelot 
1084ec561276SVivien Didelot 	return 0;
1085ec561276SVivien Didelot }
1086