xref: /OK3568_Linux_fs/kernel/drivers/net/dsa/mv88e6xxx/global2.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Marvell 88E6xxx Switch Global 2 Registers support
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2008 Marvell Semiconductor
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
8*4882a593Smuzhiyun  *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/bitfield.h>
12*4882a593Smuzhiyun #include <linux/interrupt.h>
13*4882a593Smuzhiyun #include <linux/irqdomain.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "chip.h"
16*4882a593Smuzhiyun #include "global1.h" /* for MV88E6XXX_G1_STS_IRQ_DEVICE */
17*4882a593Smuzhiyun #include "global2.h"
18*4882a593Smuzhiyun 
mv88e6xxx_g2_read(struct mv88e6xxx_chip * chip,int reg,u16 * val)19*4882a593Smuzhiyun int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun 	return mv88e6xxx_read(chip, chip->info->global2_addr, reg, val);
22*4882a593Smuzhiyun }
23*4882a593Smuzhiyun 
mv88e6xxx_g2_write(struct mv88e6xxx_chip * chip,int reg,u16 val)24*4882a593Smuzhiyun int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	return mv88e6xxx_write(chip, chip->info->global2_addr, reg, val);
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun 
mv88e6xxx_g2_wait_bit(struct mv88e6xxx_chip * chip,int reg,int bit,int val)29*4882a593Smuzhiyun int mv88e6xxx_g2_wait_bit(struct mv88e6xxx_chip *chip, int reg, int
30*4882a593Smuzhiyun 			  bit, int val)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun 	return mv88e6xxx_wait_bit(chip, chip->info->global2_addr, reg,
33*4882a593Smuzhiyun 				  bit, val);
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /* Offset 0x00: Interrupt Source Register */
37*4882a593Smuzhiyun 
mv88e6xxx_g2_int_source(struct mv88e6xxx_chip * chip,u16 * src)38*4882a593Smuzhiyun static int mv88e6xxx_g2_int_source(struct mv88e6xxx_chip *chip, u16 *src)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	/* Read (and clear most of) the Interrupt Source bits */
41*4882a593Smuzhiyun 	return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_INT_SRC, src);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun /* Offset 0x01: Interrupt Mask Register */
45*4882a593Smuzhiyun 
mv88e6xxx_g2_int_mask(struct mv88e6xxx_chip * chip,u16 mask)46*4882a593Smuzhiyun static int mv88e6xxx_g2_int_mask(struct mv88e6xxx_chip *chip, u16 mask)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_INT_MASK, mask);
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun /* Offset 0x02: Management Enable 2x */
52*4882a593Smuzhiyun 
mv88e6xxx_g2_mgmt_enable_2x(struct mv88e6xxx_chip * chip,u16 en2x)53*4882a593Smuzhiyun static int mv88e6xxx_g2_mgmt_enable_2x(struct mv88e6xxx_chip *chip, u16 en2x)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_2X, en2x);
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /* Offset 0x03: Management Enable 0x */
59*4882a593Smuzhiyun 
mv88e6xxx_g2_mgmt_enable_0x(struct mv88e6xxx_chip * chip,u16 en0x)60*4882a593Smuzhiyun static int mv88e6xxx_g2_mgmt_enable_0x(struct mv88e6xxx_chip *chip, u16 en0x)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_0X, en0x);
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /* Offset 0x05: Switch Management Register */
66*4882a593Smuzhiyun 
mv88e6xxx_g2_switch_mgmt_rsvd2cpu(struct mv88e6xxx_chip * chip,bool enable)67*4882a593Smuzhiyun static int mv88e6xxx_g2_switch_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip,
68*4882a593Smuzhiyun 					     bool enable)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	u16 val;
71*4882a593Smuzhiyun 	int err;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SWITCH_MGMT, &val);
74*4882a593Smuzhiyun 	if (err)
75*4882a593Smuzhiyun 		return err;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	if (enable)
78*4882a593Smuzhiyun 		val |= MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU;
79*4882a593Smuzhiyun 	else
80*4882a593Smuzhiyun 		val &= ~MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MGMT, val);
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun 
mv88e6185_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip * chip)85*4882a593Smuzhiyun int mv88e6185_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	int err;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	/* Consider the frames with reserved multicast destination
90*4882a593Smuzhiyun 	 * addresses matching 01:80:c2:00:00:0x as MGMT.
91*4882a593Smuzhiyun 	 */
92*4882a593Smuzhiyun 	err = mv88e6xxx_g2_mgmt_enable_0x(chip, 0xffff);
93*4882a593Smuzhiyun 	if (err)
94*4882a593Smuzhiyun 		return err;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	return mv88e6xxx_g2_switch_mgmt_rsvd2cpu(chip, true);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun 
mv88e6352_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip * chip)99*4882a593Smuzhiyun int mv88e6352_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	int err;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	/* Consider the frames with reserved multicast destination
104*4882a593Smuzhiyun 	 * addresses matching 01:80:c2:00:00:2x as MGMT.
105*4882a593Smuzhiyun 	 */
106*4882a593Smuzhiyun 	err = mv88e6xxx_g2_mgmt_enable_2x(chip, 0xffff);
107*4882a593Smuzhiyun 	if (err)
108*4882a593Smuzhiyun 		return err;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	return mv88e6185_g2_mgmt_rsvd2cpu(chip);
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun /* Offset 0x06: Device Mapping Table register */
114*4882a593Smuzhiyun 
mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip * chip,int target,int port)115*4882a593Smuzhiyun int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target,
116*4882a593Smuzhiyun 				      int port)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	u16 val = (target << 8) | (port & 0x1f);
119*4882a593Smuzhiyun 	/* Modern chips use 5 bits to define a device mapping port,
120*4882a593Smuzhiyun 	 * but bit 4 is reserved on older chips, so it is safe to use.
121*4882a593Smuzhiyun 	 */
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_DEVICE_MAPPING,
124*4882a593Smuzhiyun 				  MV88E6XXX_G2_DEVICE_MAPPING_UPDATE | val);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun /* Offset 0x07: Trunk Mask Table register */
128*4882a593Smuzhiyun 
mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip * chip,int num,bool hash,u16 mask)129*4882a593Smuzhiyun static int mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip *chip, int num,
130*4882a593Smuzhiyun 					 bool hash, u16 mask)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	u16 val = (num << 12) | (mask & mv88e6xxx_port_mask(chip));
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	if (hash)
135*4882a593Smuzhiyun 		val |= MV88E6XXX_G2_TRUNK_MASK_HASH;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_TRUNK_MASK,
138*4882a593Smuzhiyun 				  MV88E6XXX_G2_TRUNK_MASK_UPDATE | val);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun /* Offset 0x08: Trunk Mapping Table register */
142*4882a593Smuzhiyun 
mv88e6xxx_g2_trunk_mapping_write(struct mv88e6xxx_chip * chip,int id,u16 map)143*4882a593Smuzhiyun static int mv88e6xxx_g2_trunk_mapping_write(struct mv88e6xxx_chip *chip, int id,
144*4882a593Smuzhiyun 					    u16 map)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
147*4882a593Smuzhiyun 	u16 val = (id << 11) | (map & port_mask);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_TRUNK_MAPPING,
150*4882a593Smuzhiyun 				  MV88E6XXX_G2_TRUNK_MAPPING_UPDATE | val);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
mv88e6xxx_g2_trunk_clear(struct mv88e6xxx_chip * chip)153*4882a593Smuzhiyun int mv88e6xxx_g2_trunk_clear(struct mv88e6xxx_chip *chip)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
156*4882a593Smuzhiyun 	int i, err;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	/* Clear all eight possible Trunk Mask vectors */
159*4882a593Smuzhiyun 	for (i = 0; i < 8; ++i) {
160*4882a593Smuzhiyun 		err = mv88e6xxx_g2_trunk_mask_write(chip, i, false, port_mask);
161*4882a593Smuzhiyun 		if (err)
162*4882a593Smuzhiyun 			return err;
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	/* Clear all sixteen possible Trunk ID routing vectors */
166*4882a593Smuzhiyun 	for (i = 0; i < 16; ++i) {
167*4882a593Smuzhiyun 		err = mv88e6xxx_g2_trunk_mapping_write(chip, i, 0);
168*4882a593Smuzhiyun 		if (err)
169*4882a593Smuzhiyun 			return err;
170*4882a593Smuzhiyun 	}
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	return 0;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun /* Offset 0x09: Ingress Rate Command register
176*4882a593Smuzhiyun  * Offset 0x0A: Ingress Rate Data register
177*4882a593Smuzhiyun  */
178*4882a593Smuzhiyun 
mv88e6xxx_g2_irl_wait(struct mv88e6xxx_chip * chip)179*4882a593Smuzhiyun static int mv88e6xxx_g2_irl_wait(struct mv88e6xxx_chip *chip)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun 	int bit = __bf_shf(MV88E6XXX_G2_IRL_CMD_BUSY);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_IRL_CMD, bit, 0);
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun 
mv88e6xxx_g2_irl_op(struct mv88e6xxx_chip * chip,u16 op,int port,int res,int reg)186*4882a593Smuzhiyun static int mv88e6xxx_g2_irl_op(struct mv88e6xxx_chip *chip, u16 op, int port,
187*4882a593Smuzhiyun 			       int res, int reg)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun 	int err;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_IRL_CMD,
192*4882a593Smuzhiyun 				 MV88E6XXX_G2_IRL_CMD_BUSY | op | (port << 8) |
193*4882a593Smuzhiyun 				 (res << 5) | reg);
194*4882a593Smuzhiyun 	if (err)
195*4882a593Smuzhiyun 		return err;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	return mv88e6xxx_g2_irl_wait(chip);
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip * chip,int port)200*4882a593Smuzhiyun int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun 	return mv88e6xxx_g2_irl_op(chip, MV88E6352_G2_IRL_CMD_OP_INIT_ALL, port,
203*4882a593Smuzhiyun 				   0, 0);
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip * chip,int port)206*4882a593Smuzhiyun int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	return mv88e6xxx_g2_irl_op(chip, MV88E6390_G2_IRL_CMD_OP_INIT_ALL, port,
209*4882a593Smuzhiyun 				   0, 0);
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun /* Offset 0x0B: Cross-chip Port VLAN (Addr) Register
213*4882a593Smuzhiyun  * Offset 0x0C: Cross-chip Port VLAN Data Register
214*4882a593Smuzhiyun  */
215*4882a593Smuzhiyun 
mv88e6xxx_g2_pvt_op_wait(struct mv88e6xxx_chip * chip)216*4882a593Smuzhiyun static int mv88e6xxx_g2_pvt_op_wait(struct mv88e6xxx_chip *chip)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	int bit = __bf_shf(MV88E6XXX_G2_PVT_ADDR_BUSY);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_PVT_ADDR, bit, 0);
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun 
mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip * chip,int src_dev,int src_port,u16 op)223*4882a593Smuzhiyun static int mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip *chip, int src_dev,
224*4882a593Smuzhiyun 			       int src_port, u16 op)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun 	int err;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	/* 9-bit Cross-chip PVT pointer: with MV88E6XXX_G2_MISC_5_BIT_PORT
229*4882a593Smuzhiyun 	 * cleared, source device is 5-bit, source port is 4-bit.
230*4882a593Smuzhiyun 	 */
231*4882a593Smuzhiyun 	op |= MV88E6XXX_G2_PVT_ADDR_BUSY;
232*4882a593Smuzhiyun 	op |= (src_dev & 0x1f) << 4;
233*4882a593Smuzhiyun 	op |= (src_port & 0xf);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_ADDR, op);
236*4882a593Smuzhiyun 	if (err)
237*4882a593Smuzhiyun 		return err;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	return mv88e6xxx_g2_pvt_op_wait(chip);
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip * chip,int src_dev,int src_port,u16 data)242*4882a593Smuzhiyun int mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev,
243*4882a593Smuzhiyun 			   int src_port, u16 data)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	int err;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	err = mv88e6xxx_g2_pvt_op_wait(chip);
248*4882a593Smuzhiyun 	if (err)
249*4882a593Smuzhiyun 		return err;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_DATA, data);
252*4882a593Smuzhiyun 	if (err)
253*4882a593Smuzhiyun 		return err;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	return mv88e6xxx_g2_pvt_op(chip, src_dev, src_port,
256*4882a593Smuzhiyun 				   MV88E6XXX_G2_PVT_ADDR_OP_WRITE_PVLAN);
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun /* Offset 0x0D: Switch MAC/WoL/WoF register */
260*4882a593Smuzhiyun 
mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip * chip,unsigned int pointer,u8 data)261*4882a593Smuzhiyun static int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip,
262*4882a593Smuzhiyun 					 unsigned int pointer, u8 data)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	u16 val = (pointer << 8) | data;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MAC,
267*4882a593Smuzhiyun 				  MV88E6XXX_G2_SWITCH_MAC_UPDATE | val);
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun 
mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip * chip,u8 * addr)270*4882a593Smuzhiyun int mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun 	int i, err;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	for (i = 0; i < 6; i++) {
275*4882a593Smuzhiyun 		err = mv88e6xxx_g2_switch_mac_write(chip, i, addr[i]);
276*4882a593Smuzhiyun 		if (err)
277*4882a593Smuzhiyun 			break;
278*4882a593Smuzhiyun 	}
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	return err;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun /* Offset 0x0E: ATU Statistics */
284*4882a593Smuzhiyun 
mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip * chip,u16 kind,u16 bin)285*4882a593Smuzhiyun int mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip *chip, u16 kind, u16 bin)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_ATU_STATS,
288*4882a593Smuzhiyun 				  kind | bin);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip * chip,u16 * stats)291*4882a593Smuzhiyun int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip, u16 *stats)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun 	return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_ATU_STATS, stats);
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun /* Offset 0x0F: Priority Override Table */
297*4882a593Smuzhiyun 
mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip * chip,int pointer,u8 data)298*4882a593Smuzhiyun static int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer,
299*4882a593Smuzhiyun 				  u8 data)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun 	u16 val = (pointer << 8) | (data & 0x7);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PRIO_OVERRIDE,
304*4882a593Smuzhiyun 				  MV88E6XXX_G2_PRIO_OVERRIDE_UPDATE | val);
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip * chip)307*4882a593Smuzhiyun int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	int i, err;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	/* Clear all sixteen possible Priority Override entries */
312*4882a593Smuzhiyun 	for (i = 0; i < 16; i++) {
313*4882a593Smuzhiyun 		err = mv88e6xxx_g2_pot_write(chip, i, 0);
314*4882a593Smuzhiyun 		if (err)
315*4882a593Smuzhiyun 			break;
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	return err;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun /* Offset 0x14: EEPROM Command
322*4882a593Smuzhiyun  * Offset 0x15: EEPROM Data (for 16-bit data access)
323*4882a593Smuzhiyun  * Offset 0x15: EEPROM Addr (for 8-bit data access)
324*4882a593Smuzhiyun  */
325*4882a593Smuzhiyun 
mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip * chip)326*4882a593Smuzhiyun static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun 	int bit = __bf_shf(MV88E6XXX_G2_EEPROM_CMD_BUSY);
329*4882a593Smuzhiyun 	int err;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	err = mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_EEPROM_CMD, bit, 0);
332*4882a593Smuzhiyun 	if (err)
333*4882a593Smuzhiyun 		return err;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	bit = __bf_shf(MV88E6XXX_G2_EEPROM_CMD_RUNNING);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_EEPROM_CMD, bit, 0);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip * chip,u16 cmd)340*4882a593Smuzhiyun static int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun 	int err;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_EEPROM_CMD,
345*4882a593Smuzhiyun 				 MV88E6XXX_G2_EEPROM_CMD_BUSY | cmd);
346*4882a593Smuzhiyun 	if (err)
347*4882a593Smuzhiyun 		return err;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	return mv88e6xxx_g2_eeprom_wait(chip);
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun 
mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip * chip,u16 addr,u8 * data)352*4882a593Smuzhiyun static int mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip *chip,
353*4882a593Smuzhiyun 				     u16 addr, u8 *data)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun 	u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ;
356*4882a593Smuzhiyun 	int err;
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	err = mv88e6xxx_g2_eeprom_wait(chip);
359*4882a593Smuzhiyun 	if (err)
360*4882a593Smuzhiyun 		return err;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr);
363*4882a593Smuzhiyun 	if (err)
364*4882a593Smuzhiyun 		return err;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
367*4882a593Smuzhiyun 	if (err)
368*4882a593Smuzhiyun 		return err;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &cmd);
371*4882a593Smuzhiyun 	if (err)
372*4882a593Smuzhiyun 		return err;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	*data = cmd & 0xff;
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	return 0;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun 
mv88e6xxx_g2_eeprom_write8(struct mv88e6xxx_chip * chip,u16 addr,u8 data)379*4882a593Smuzhiyun static int mv88e6xxx_g2_eeprom_write8(struct mv88e6xxx_chip *chip,
380*4882a593Smuzhiyun 				      u16 addr, u8 data)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun 	u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE |
383*4882a593Smuzhiyun 		MV88E6XXX_G2_EEPROM_CMD_WRITE_EN;
384*4882a593Smuzhiyun 	int err;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	err = mv88e6xxx_g2_eeprom_wait(chip);
387*4882a593Smuzhiyun 	if (err)
388*4882a593Smuzhiyun 		return err;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr);
391*4882a593Smuzhiyun 	if (err)
392*4882a593Smuzhiyun 		return err;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	return mv88e6xxx_g2_eeprom_cmd(chip, cmd | data);
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun 
mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip * chip,u8 addr,u16 * data)397*4882a593Smuzhiyun static int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip,
398*4882a593Smuzhiyun 				      u8 addr, u16 *data)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun 	u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ | addr;
401*4882a593Smuzhiyun 	int err;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	err = mv88e6xxx_g2_eeprom_wait(chip);
404*4882a593Smuzhiyun 	if (err)
405*4882a593Smuzhiyun 		return err;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
408*4882a593Smuzhiyun 	if (err)
409*4882a593Smuzhiyun 		return err;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	return mv88e6xxx_g2_read(chip, MV88E6352_G2_EEPROM_DATA, data);
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun 
mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip * chip,u8 addr,u16 data)414*4882a593Smuzhiyun static int mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip *chip,
415*4882a593Smuzhiyun 				       u8 addr, u16 data)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun 	u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE | addr;
418*4882a593Smuzhiyun 	int err;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	err = mv88e6xxx_g2_eeprom_wait(chip);
421*4882a593Smuzhiyun 	if (err)
422*4882a593Smuzhiyun 		return err;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	err = mv88e6xxx_g2_write(chip, MV88E6352_G2_EEPROM_DATA, data);
425*4882a593Smuzhiyun 	if (err)
426*4882a593Smuzhiyun 		return err;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	return mv88e6xxx_g2_eeprom_cmd(chip, cmd);
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun 
mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip * chip,struct ethtool_eeprom * eeprom,u8 * data)431*4882a593Smuzhiyun int mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip *chip,
432*4882a593Smuzhiyun 			     struct ethtool_eeprom *eeprom, u8 *data)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun 	unsigned int offset = eeprom->offset;
435*4882a593Smuzhiyun 	unsigned int len = eeprom->len;
436*4882a593Smuzhiyun 	int err;
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	eeprom->len = 0;
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	while (len) {
441*4882a593Smuzhiyun 		err = mv88e6xxx_g2_eeprom_read8(chip, offset, data);
442*4882a593Smuzhiyun 		if (err)
443*4882a593Smuzhiyun 			return err;
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 		eeprom->len++;
446*4882a593Smuzhiyun 		offset++;
447*4882a593Smuzhiyun 		data++;
448*4882a593Smuzhiyun 		len--;
449*4882a593Smuzhiyun 	}
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	return 0;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun 
mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip * chip,struct ethtool_eeprom * eeprom,u8 * data)454*4882a593Smuzhiyun int mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip *chip,
455*4882a593Smuzhiyun 			     struct ethtool_eeprom *eeprom, u8 *data)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun 	unsigned int offset = eeprom->offset;
458*4882a593Smuzhiyun 	unsigned int len = eeprom->len;
459*4882a593Smuzhiyun 	int err;
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	eeprom->len = 0;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	while (len) {
464*4882a593Smuzhiyun 		err = mv88e6xxx_g2_eeprom_write8(chip, offset, *data);
465*4882a593Smuzhiyun 		if (err)
466*4882a593Smuzhiyun 			return err;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 		eeprom->len++;
469*4882a593Smuzhiyun 		offset++;
470*4882a593Smuzhiyun 		data++;
471*4882a593Smuzhiyun 		len--;
472*4882a593Smuzhiyun 	}
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	return 0;
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun 
mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip * chip,struct ethtool_eeprom * eeprom,u8 * data)477*4882a593Smuzhiyun int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
478*4882a593Smuzhiyun 			      struct ethtool_eeprom *eeprom, u8 *data)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun 	unsigned int offset = eeprom->offset;
481*4882a593Smuzhiyun 	unsigned int len = eeprom->len;
482*4882a593Smuzhiyun 	u16 val;
483*4882a593Smuzhiyun 	int err;
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	eeprom->len = 0;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	if (offset & 1) {
488*4882a593Smuzhiyun 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
489*4882a593Smuzhiyun 		if (err)
490*4882a593Smuzhiyun 			return err;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 		*data++ = (val >> 8) & 0xff;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 		offset++;
495*4882a593Smuzhiyun 		len--;
496*4882a593Smuzhiyun 		eeprom->len++;
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	while (len >= 2) {
500*4882a593Smuzhiyun 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
501*4882a593Smuzhiyun 		if (err)
502*4882a593Smuzhiyun 			return err;
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 		*data++ = val & 0xff;
505*4882a593Smuzhiyun 		*data++ = (val >> 8) & 0xff;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 		offset += 2;
508*4882a593Smuzhiyun 		len -= 2;
509*4882a593Smuzhiyun 		eeprom->len += 2;
510*4882a593Smuzhiyun 	}
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	if (len) {
513*4882a593Smuzhiyun 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
514*4882a593Smuzhiyun 		if (err)
515*4882a593Smuzhiyun 			return err;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 		*data++ = val & 0xff;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 		offset++;
520*4882a593Smuzhiyun 		len--;
521*4882a593Smuzhiyun 		eeprom->len++;
522*4882a593Smuzhiyun 	}
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	return 0;
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun 
mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip * chip,struct ethtool_eeprom * eeprom,u8 * data)527*4882a593Smuzhiyun int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
528*4882a593Smuzhiyun 			      struct ethtool_eeprom *eeprom, u8 *data)
529*4882a593Smuzhiyun {
530*4882a593Smuzhiyun 	unsigned int offset = eeprom->offset;
531*4882a593Smuzhiyun 	unsigned int len = eeprom->len;
532*4882a593Smuzhiyun 	u16 val;
533*4882a593Smuzhiyun 	int err;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	/* Ensure the RO WriteEn bit is set */
536*4882a593Smuzhiyun 	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &val);
537*4882a593Smuzhiyun 	if (err)
538*4882a593Smuzhiyun 		return err;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	if (!(val & MV88E6XXX_G2_EEPROM_CMD_WRITE_EN))
541*4882a593Smuzhiyun 		return -EROFS;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	eeprom->len = 0;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	if (offset & 1) {
546*4882a593Smuzhiyun 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
547*4882a593Smuzhiyun 		if (err)
548*4882a593Smuzhiyun 			return err;
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 		val = (*data++ << 8) | (val & 0xff);
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 		err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
553*4882a593Smuzhiyun 		if (err)
554*4882a593Smuzhiyun 			return err;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 		offset++;
557*4882a593Smuzhiyun 		len--;
558*4882a593Smuzhiyun 		eeprom->len++;
559*4882a593Smuzhiyun 	}
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	while (len >= 2) {
562*4882a593Smuzhiyun 		val = *data++;
563*4882a593Smuzhiyun 		val |= *data++ << 8;
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 		err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
566*4882a593Smuzhiyun 		if (err)
567*4882a593Smuzhiyun 			return err;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 		offset += 2;
570*4882a593Smuzhiyun 		len -= 2;
571*4882a593Smuzhiyun 		eeprom->len += 2;
572*4882a593Smuzhiyun 	}
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	if (len) {
575*4882a593Smuzhiyun 		err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
576*4882a593Smuzhiyun 		if (err)
577*4882a593Smuzhiyun 			return err;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 		val = (val & 0xff00) | *data++;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 		err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
582*4882a593Smuzhiyun 		if (err)
583*4882a593Smuzhiyun 			return err;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 		offset++;
586*4882a593Smuzhiyun 		len--;
587*4882a593Smuzhiyun 		eeprom->len++;
588*4882a593Smuzhiyun 	}
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	return 0;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun /* Offset 0x18: SMI PHY Command Register
594*4882a593Smuzhiyun  * Offset 0x19: SMI PHY Data Register
595*4882a593Smuzhiyun  */
596*4882a593Smuzhiyun 
mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip * chip)597*4882a593Smuzhiyun static int mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip *chip)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun 	int bit = __bf_shf(MV88E6XXX_G2_SMI_PHY_CMD_BUSY);
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_SMI_PHY_CMD, bit, 0);
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip * chip,u16 cmd)604*4882a593Smuzhiyun static int mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun 	int err;
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_CMD,
609*4882a593Smuzhiyun 				 MV88E6XXX_G2_SMI_PHY_CMD_BUSY | cmd);
610*4882a593Smuzhiyun 	if (err)
611*4882a593Smuzhiyun 		return err;
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	return mv88e6xxx_g2_smi_phy_wait(chip);
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun 
mv88e6xxx_g2_smi_phy_access(struct mv88e6xxx_chip * chip,bool external,bool c45,u16 op,int dev,int reg)616*4882a593Smuzhiyun static int mv88e6xxx_g2_smi_phy_access(struct mv88e6xxx_chip *chip,
617*4882a593Smuzhiyun 				       bool external, bool c45, u16 op, int dev,
618*4882a593Smuzhiyun 				       int reg)
619*4882a593Smuzhiyun {
620*4882a593Smuzhiyun 	u16 cmd = op;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	if (external)
623*4882a593Smuzhiyun 		cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_EXTERNAL;
624*4882a593Smuzhiyun 	else
625*4882a593Smuzhiyun 		cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_INTERNAL; /* empty mask */
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 	if (c45)
628*4882a593Smuzhiyun 		cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_45; /* empty mask */
629*4882a593Smuzhiyun 	else
630*4882a593Smuzhiyun 		cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_22;
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	dev <<= __bf_shf(MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK);
633*4882a593Smuzhiyun 	cmd |= dev & MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK;
634*4882a593Smuzhiyun 	cmd |= reg & MV88E6XXX_G2_SMI_PHY_CMD_REG_ADDR_MASK;
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	return mv88e6xxx_g2_smi_phy_cmd(chip, cmd);
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun 
mv88e6xxx_g2_smi_phy_access_c22(struct mv88e6xxx_chip * chip,bool external,u16 op,int dev,int reg)639*4882a593Smuzhiyun static int mv88e6xxx_g2_smi_phy_access_c22(struct mv88e6xxx_chip *chip,
640*4882a593Smuzhiyun 					   bool external, u16 op, int dev,
641*4882a593Smuzhiyun 					   int reg)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun 	return mv88e6xxx_g2_smi_phy_access(chip, external, false, op, dev, reg);
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun /* IEEE 802.3 Clause 22 Read Data Register */
mv88e6xxx_g2_smi_phy_read_data_c22(struct mv88e6xxx_chip * chip,bool external,int dev,int reg,u16 * data)647*4882a593Smuzhiyun static int mv88e6xxx_g2_smi_phy_read_data_c22(struct mv88e6xxx_chip *chip,
648*4882a593Smuzhiyun 					      bool external, int dev, int reg,
649*4882a593Smuzhiyun 					      u16 *data)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_READ_DATA;
652*4882a593Smuzhiyun 	int err;
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	err = mv88e6xxx_g2_smi_phy_wait(chip);
655*4882a593Smuzhiyun 	if (err)
656*4882a593Smuzhiyun 		return err;
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	err = mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
659*4882a593Smuzhiyun 	if (err)
660*4882a593Smuzhiyun 		return err;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun /* IEEE 802.3 Clause 22 Write Data Register */
mv88e6xxx_g2_smi_phy_write_data_c22(struct mv88e6xxx_chip * chip,bool external,int dev,int reg,u16 data)666*4882a593Smuzhiyun static int mv88e6xxx_g2_smi_phy_write_data_c22(struct mv88e6xxx_chip *chip,
667*4882a593Smuzhiyun 					       bool external, int dev, int reg,
668*4882a593Smuzhiyun 					       u16 data)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_WRITE_DATA;
671*4882a593Smuzhiyun 	int err;
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 	err = mv88e6xxx_g2_smi_phy_wait(chip);
674*4882a593Smuzhiyun 	if (err)
675*4882a593Smuzhiyun 		return err;
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
678*4882a593Smuzhiyun 	if (err)
679*4882a593Smuzhiyun 		return err;
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun 	return mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
682*4882a593Smuzhiyun }
683*4882a593Smuzhiyun 
mv88e6xxx_g2_smi_phy_access_c45(struct mv88e6xxx_chip * chip,bool external,u16 op,int port,int dev)684*4882a593Smuzhiyun static int mv88e6xxx_g2_smi_phy_access_c45(struct mv88e6xxx_chip *chip,
685*4882a593Smuzhiyun 					   bool external, u16 op, int port,
686*4882a593Smuzhiyun 					   int dev)
687*4882a593Smuzhiyun {
688*4882a593Smuzhiyun 	return mv88e6xxx_g2_smi_phy_access(chip, external, true, op, port, dev);
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun /* IEEE 802.3 Clause 45 Write Address Register */
mv88e6xxx_g2_smi_phy_write_addr_c45(struct mv88e6xxx_chip * chip,bool external,int port,int dev,int addr)692*4882a593Smuzhiyun static int mv88e6xxx_g2_smi_phy_write_addr_c45(struct mv88e6xxx_chip *chip,
693*4882a593Smuzhiyun 					       bool external, int port, int dev,
694*4882a593Smuzhiyun 					       int addr)
695*4882a593Smuzhiyun {
696*4882a593Smuzhiyun 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_ADDR;
697*4882a593Smuzhiyun 	int err;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	err = mv88e6xxx_g2_smi_phy_wait(chip);
700*4882a593Smuzhiyun 	if (err)
701*4882a593Smuzhiyun 		return err;
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, addr);
704*4882a593Smuzhiyun 	if (err)
705*4882a593Smuzhiyun 		return err;
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun /* IEEE 802.3 Clause 45 Read Data Register */
mv88e6xxx_g2_smi_phy_read_data_c45(struct mv88e6xxx_chip * chip,bool external,int port,int dev,u16 * data)711*4882a593Smuzhiyun static int mv88e6xxx_g2_smi_phy_read_data_c45(struct mv88e6xxx_chip *chip,
712*4882a593Smuzhiyun 					      bool external, int port, int dev,
713*4882a593Smuzhiyun 					      u16 *data)
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_READ_DATA;
716*4882a593Smuzhiyun 	int err;
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	err = mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
719*4882a593Smuzhiyun 	if (err)
720*4882a593Smuzhiyun 		return err;
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 	return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
723*4882a593Smuzhiyun }
724*4882a593Smuzhiyun 
mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip * chip,bool external,int port,int reg,u16 * data)725*4882a593Smuzhiyun static int mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip,
726*4882a593Smuzhiyun 					 bool external, int port, int reg,
727*4882a593Smuzhiyun 					 u16 *data)
728*4882a593Smuzhiyun {
729*4882a593Smuzhiyun 	int dev = (reg >> 16) & 0x1f;
730*4882a593Smuzhiyun 	int addr = reg & 0xffff;
731*4882a593Smuzhiyun 	int err;
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev,
734*4882a593Smuzhiyun 						  addr);
735*4882a593Smuzhiyun 	if (err)
736*4882a593Smuzhiyun 		return err;
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	return mv88e6xxx_g2_smi_phy_read_data_c45(chip, external, port, dev,
739*4882a593Smuzhiyun 						  data);
740*4882a593Smuzhiyun }
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun /* IEEE 802.3 Clause 45 Write Data Register */
mv88e6xxx_g2_smi_phy_write_data_c45(struct mv88e6xxx_chip * chip,bool external,int port,int dev,u16 data)743*4882a593Smuzhiyun static int mv88e6xxx_g2_smi_phy_write_data_c45(struct mv88e6xxx_chip *chip,
744*4882a593Smuzhiyun 					       bool external, int port, int dev,
745*4882a593Smuzhiyun 					       u16 data)
746*4882a593Smuzhiyun {
747*4882a593Smuzhiyun 	u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_DATA;
748*4882a593Smuzhiyun 	int err;
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 	err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
751*4882a593Smuzhiyun 	if (err)
752*4882a593Smuzhiyun 		return err;
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun 
mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip * chip,bool external,int port,int reg,u16 data)757*4882a593Smuzhiyun static int mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip,
758*4882a593Smuzhiyun 					  bool external, int port, int reg,
759*4882a593Smuzhiyun 					  u16 data)
760*4882a593Smuzhiyun {
761*4882a593Smuzhiyun 	int dev = (reg >> 16) & 0x1f;
762*4882a593Smuzhiyun 	int addr = reg & 0xffff;
763*4882a593Smuzhiyun 	int err;
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 	err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev,
766*4882a593Smuzhiyun 						  addr);
767*4882a593Smuzhiyun 	if (err)
768*4882a593Smuzhiyun 		return err;
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	return mv88e6xxx_g2_smi_phy_write_data_c45(chip, external, port, dev,
771*4882a593Smuzhiyun 						   data);
772*4882a593Smuzhiyun }
773*4882a593Smuzhiyun 
mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip * chip,struct mii_bus * bus,int addr,int reg,u16 * val)774*4882a593Smuzhiyun int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
775*4882a593Smuzhiyun 			      int addr, int reg, u16 *val)
776*4882a593Smuzhiyun {
777*4882a593Smuzhiyun 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
778*4882a593Smuzhiyun 	bool external = mdio_bus->external;
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	if (reg & MII_ADDR_C45)
781*4882a593Smuzhiyun 		return mv88e6xxx_g2_smi_phy_read_c45(chip, external, addr, reg,
782*4882a593Smuzhiyun 						     val);
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	return mv88e6xxx_g2_smi_phy_read_data_c22(chip, external, addr, reg,
785*4882a593Smuzhiyun 						  val);
786*4882a593Smuzhiyun }
787*4882a593Smuzhiyun 
mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip * chip,struct mii_bus * bus,int addr,int reg,u16 val)788*4882a593Smuzhiyun int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
789*4882a593Smuzhiyun 			       int addr, int reg, u16 val)
790*4882a593Smuzhiyun {
791*4882a593Smuzhiyun 	struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
792*4882a593Smuzhiyun 	bool external = mdio_bus->external;
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	if (reg & MII_ADDR_C45)
795*4882a593Smuzhiyun 		return mv88e6xxx_g2_smi_phy_write_c45(chip, external, addr, reg,
796*4882a593Smuzhiyun 						      val);
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	return mv88e6xxx_g2_smi_phy_write_data_c22(chip, external, addr, reg,
799*4882a593Smuzhiyun 						   val);
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun /* Offset 0x1B: Watchdog Control */
mv88e6097_watchdog_action(struct mv88e6xxx_chip * chip,int irq)803*4882a593Smuzhiyun static int mv88e6097_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
804*4882a593Smuzhiyun {
805*4882a593Smuzhiyun 	u16 reg;
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, &reg);
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	dev_info(chip->dev, "Watchdog event: 0x%04x", reg);
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 	return IRQ_HANDLED;
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun 
mv88e6097_watchdog_free(struct mv88e6xxx_chip * chip)814*4882a593Smuzhiyun static void mv88e6097_watchdog_free(struct mv88e6xxx_chip *chip)
815*4882a593Smuzhiyun {
816*4882a593Smuzhiyun 	u16 reg;
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, &reg);
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 	reg &= ~(MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
821*4882a593Smuzhiyun 		 MV88E6352_G2_WDOG_CTL_QC_ENABLE);
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 	mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL, reg);
824*4882a593Smuzhiyun }
825*4882a593Smuzhiyun 
mv88e6097_watchdog_setup(struct mv88e6xxx_chip * chip)826*4882a593Smuzhiyun static int mv88e6097_watchdog_setup(struct mv88e6xxx_chip *chip)
827*4882a593Smuzhiyun {
828*4882a593Smuzhiyun 	return mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL,
829*4882a593Smuzhiyun 				  MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
830*4882a593Smuzhiyun 				  MV88E6352_G2_WDOG_CTL_QC_ENABLE |
831*4882a593Smuzhiyun 				  MV88E6352_G2_WDOG_CTL_SWRESET);
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {
835*4882a593Smuzhiyun 	.irq_action = mv88e6097_watchdog_action,
836*4882a593Smuzhiyun 	.irq_setup = mv88e6097_watchdog_setup,
837*4882a593Smuzhiyun 	.irq_free = mv88e6097_watchdog_free,
838*4882a593Smuzhiyun };
839*4882a593Smuzhiyun 
mv88e6250_watchdog_free(struct mv88e6xxx_chip * chip)840*4882a593Smuzhiyun static void mv88e6250_watchdog_free(struct mv88e6xxx_chip *chip)
841*4882a593Smuzhiyun {
842*4882a593Smuzhiyun 	u16 reg;
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 	mv88e6xxx_g2_read(chip, MV88E6250_G2_WDOG_CTL, &reg);
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 	reg &= ~(MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE |
847*4882a593Smuzhiyun 		 MV88E6250_G2_WDOG_CTL_QC_ENABLE);
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	mv88e6xxx_g2_write(chip, MV88E6250_G2_WDOG_CTL, reg);
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun 
mv88e6250_watchdog_setup(struct mv88e6xxx_chip * chip)852*4882a593Smuzhiyun static int mv88e6250_watchdog_setup(struct mv88e6xxx_chip *chip)
853*4882a593Smuzhiyun {
854*4882a593Smuzhiyun 	return mv88e6xxx_g2_write(chip, MV88E6250_G2_WDOG_CTL,
855*4882a593Smuzhiyun 				  MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE |
856*4882a593Smuzhiyun 				  MV88E6250_G2_WDOG_CTL_QC_ENABLE |
857*4882a593Smuzhiyun 				  MV88E6250_G2_WDOG_CTL_SWRESET);
858*4882a593Smuzhiyun }
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops = {
861*4882a593Smuzhiyun 	.irq_action = mv88e6097_watchdog_action,
862*4882a593Smuzhiyun 	.irq_setup = mv88e6250_watchdog_setup,
863*4882a593Smuzhiyun 	.irq_free = mv88e6250_watchdog_free,
864*4882a593Smuzhiyun };
865*4882a593Smuzhiyun 
mv88e6390_watchdog_setup(struct mv88e6xxx_chip * chip)866*4882a593Smuzhiyun static int mv88e6390_watchdog_setup(struct mv88e6xxx_chip *chip)
867*4882a593Smuzhiyun {
868*4882a593Smuzhiyun 	return mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
869*4882a593Smuzhiyun 				  MV88E6390_G2_WDOG_CTL_UPDATE |
870*4882a593Smuzhiyun 				  MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE |
871*4882a593Smuzhiyun 				  MV88E6390_G2_WDOG_CTL_CUT_THROUGH |
872*4882a593Smuzhiyun 				  MV88E6390_G2_WDOG_CTL_QUEUE_CONTROLLER |
873*4882a593Smuzhiyun 				  MV88E6390_G2_WDOG_CTL_EGRESS |
874*4882a593Smuzhiyun 				  MV88E6390_G2_WDOG_CTL_FORCE_IRQ);
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun 
mv88e6390_watchdog_action(struct mv88e6xxx_chip * chip,int irq)877*4882a593Smuzhiyun static int mv88e6390_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
878*4882a593Smuzhiyun {
879*4882a593Smuzhiyun 	u16 reg;
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
882*4882a593Smuzhiyun 			   MV88E6390_G2_WDOG_CTL_PTR_EVENT);
883*4882a593Smuzhiyun 	mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, &reg);
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	dev_info(chip->dev, "Watchdog event: 0x%04x",
886*4882a593Smuzhiyun 		 reg & MV88E6390_G2_WDOG_CTL_DATA_MASK);
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 	mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
889*4882a593Smuzhiyun 			   MV88E6390_G2_WDOG_CTL_PTR_HISTORY);
890*4882a593Smuzhiyun 	mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, &reg);
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 	dev_info(chip->dev, "Watchdog history: 0x%04x",
893*4882a593Smuzhiyun 		 reg & MV88E6390_G2_WDOG_CTL_DATA_MASK);
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 	/* Trigger a software reset to try to recover the switch */
896*4882a593Smuzhiyun 	if (chip->info->ops->reset)
897*4882a593Smuzhiyun 		chip->info->ops->reset(chip);
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 	mv88e6390_watchdog_setup(chip);
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun 	return IRQ_HANDLED;
902*4882a593Smuzhiyun }
903*4882a593Smuzhiyun 
mv88e6390_watchdog_free(struct mv88e6xxx_chip * chip)904*4882a593Smuzhiyun static void mv88e6390_watchdog_free(struct mv88e6xxx_chip *chip)
905*4882a593Smuzhiyun {
906*4882a593Smuzhiyun 	mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
907*4882a593Smuzhiyun 			   MV88E6390_G2_WDOG_CTL_UPDATE |
908*4882a593Smuzhiyun 			   MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE);
909*4882a593Smuzhiyun }
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {
912*4882a593Smuzhiyun 	.irq_action = mv88e6390_watchdog_action,
913*4882a593Smuzhiyun 	.irq_setup = mv88e6390_watchdog_setup,
914*4882a593Smuzhiyun 	.irq_free = mv88e6390_watchdog_free,
915*4882a593Smuzhiyun };
916*4882a593Smuzhiyun 
mv88e6xxx_g2_watchdog_thread_fn(int irq,void * dev_id)917*4882a593Smuzhiyun static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id)
918*4882a593Smuzhiyun {
919*4882a593Smuzhiyun 	struct mv88e6xxx_chip *chip = dev_id;
920*4882a593Smuzhiyun 	irqreturn_t ret = IRQ_NONE;
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 	mv88e6xxx_reg_lock(chip);
923*4882a593Smuzhiyun 	if (chip->info->ops->watchdog_ops->irq_action)
924*4882a593Smuzhiyun 		ret = chip->info->ops->watchdog_ops->irq_action(chip, irq);
925*4882a593Smuzhiyun 	mv88e6xxx_reg_unlock(chip);
926*4882a593Smuzhiyun 
927*4882a593Smuzhiyun 	return ret;
928*4882a593Smuzhiyun }
929*4882a593Smuzhiyun 
mv88e6xxx_g2_watchdog_free(struct mv88e6xxx_chip * chip)930*4882a593Smuzhiyun static void mv88e6xxx_g2_watchdog_free(struct mv88e6xxx_chip *chip)
931*4882a593Smuzhiyun {
932*4882a593Smuzhiyun 	mv88e6xxx_reg_lock(chip);
933*4882a593Smuzhiyun 	if (chip->info->ops->watchdog_ops->irq_free)
934*4882a593Smuzhiyun 		chip->info->ops->watchdog_ops->irq_free(chip);
935*4882a593Smuzhiyun 	mv88e6xxx_reg_unlock(chip);
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	free_irq(chip->watchdog_irq, chip);
938*4882a593Smuzhiyun 	irq_dispose_mapping(chip->watchdog_irq);
939*4882a593Smuzhiyun }
940*4882a593Smuzhiyun 
mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip * chip)941*4882a593Smuzhiyun static int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip)
942*4882a593Smuzhiyun {
943*4882a593Smuzhiyun 	int err;
944*4882a593Smuzhiyun 
945*4882a593Smuzhiyun 	chip->watchdog_irq = irq_find_mapping(chip->g2_irq.domain,
946*4882a593Smuzhiyun 					      MV88E6XXX_G2_INT_SOURCE_WATCHDOG);
947*4882a593Smuzhiyun 	if (chip->watchdog_irq < 0)
948*4882a593Smuzhiyun 		return chip->watchdog_irq;
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun 	snprintf(chip->watchdog_irq_name, sizeof(chip->watchdog_irq_name),
951*4882a593Smuzhiyun 		 "mv88e6xxx-%s-watchdog", dev_name(chip->dev));
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	err = request_threaded_irq(chip->watchdog_irq, NULL,
954*4882a593Smuzhiyun 				   mv88e6xxx_g2_watchdog_thread_fn,
955*4882a593Smuzhiyun 				   IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
956*4882a593Smuzhiyun 				   chip->watchdog_irq_name, chip);
957*4882a593Smuzhiyun 	if (err)
958*4882a593Smuzhiyun 		return err;
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 	mv88e6xxx_reg_lock(chip);
961*4882a593Smuzhiyun 	if (chip->info->ops->watchdog_ops->irq_setup)
962*4882a593Smuzhiyun 		err = chip->info->ops->watchdog_ops->irq_setup(chip);
963*4882a593Smuzhiyun 	mv88e6xxx_reg_unlock(chip);
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	return err;
966*4882a593Smuzhiyun }
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun /* Offset 0x1D: Misc Register */
969*4882a593Smuzhiyun 
mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip * chip,bool port_5_bit)970*4882a593Smuzhiyun static int mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip *chip,
971*4882a593Smuzhiyun 					bool port_5_bit)
972*4882a593Smuzhiyun {
973*4882a593Smuzhiyun 	u16 val;
974*4882a593Smuzhiyun 	int err;
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_MISC, &val);
977*4882a593Smuzhiyun 	if (err)
978*4882a593Smuzhiyun 		return err;
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun 	if (port_5_bit)
981*4882a593Smuzhiyun 		val |= MV88E6XXX_G2_MISC_5_BIT_PORT;
982*4882a593Smuzhiyun 	else
983*4882a593Smuzhiyun 		val &= ~MV88E6XXX_G2_MISC_5_BIT_PORT;
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 	return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MISC, val);
986*4882a593Smuzhiyun }
987*4882a593Smuzhiyun 
mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip * chip)988*4882a593Smuzhiyun int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip)
989*4882a593Smuzhiyun {
990*4882a593Smuzhiyun 	return mv88e6xxx_g2_misc_5_bit_port(chip, false);
991*4882a593Smuzhiyun }
992*4882a593Smuzhiyun 
mv88e6xxx_g2_irq_mask(struct irq_data * d)993*4882a593Smuzhiyun static void mv88e6xxx_g2_irq_mask(struct irq_data *d)
994*4882a593Smuzhiyun {
995*4882a593Smuzhiyun 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
996*4882a593Smuzhiyun 	unsigned int n = d->hwirq;
997*4882a593Smuzhiyun 
998*4882a593Smuzhiyun 	chip->g2_irq.masked |= (1 << n);
999*4882a593Smuzhiyun }
1000*4882a593Smuzhiyun 
mv88e6xxx_g2_irq_unmask(struct irq_data * d)1001*4882a593Smuzhiyun static void mv88e6xxx_g2_irq_unmask(struct irq_data *d)
1002*4882a593Smuzhiyun {
1003*4882a593Smuzhiyun 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
1004*4882a593Smuzhiyun 	unsigned int n = d->hwirq;
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun 	chip->g2_irq.masked &= ~(1 << n);
1007*4882a593Smuzhiyun }
1008*4882a593Smuzhiyun 
mv88e6xxx_g2_irq_thread_fn(int irq,void * dev_id)1009*4882a593Smuzhiyun static irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id)
1010*4882a593Smuzhiyun {
1011*4882a593Smuzhiyun 	struct mv88e6xxx_chip *chip = dev_id;
1012*4882a593Smuzhiyun 	unsigned int nhandled = 0;
1013*4882a593Smuzhiyun 	unsigned int sub_irq;
1014*4882a593Smuzhiyun 	unsigned int n;
1015*4882a593Smuzhiyun 	int err;
1016*4882a593Smuzhiyun 	u16 reg;
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	mv88e6xxx_reg_lock(chip);
1019*4882a593Smuzhiyun 	err = mv88e6xxx_g2_int_source(chip, &reg);
1020*4882a593Smuzhiyun 	mv88e6xxx_reg_unlock(chip);
1021*4882a593Smuzhiyun 	if (err)
1022*4882a593Smuzhiyun 		goto out;
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun 	for (n = 0; n < 16; ++n) {
1025*4882a593Smuzhiyun 		if (reg & (1 << n)) {
1026*4882a593Smuzhiyun 			sub_irq = irq_find_mapping(chip->g2_irq.domain, n);
1027*4882a593Smuzhiyun 			handle_nested_irq(sub_irq);
1028*4882a593Smuzhiyun 			++nhandled;
1029*4882a593Smuzhiyun 		}
1030*4882a593Smuzhiyun 	}
1031*4882a593Smuzhiyun out:
1032*4882a593Smuzhiyun 	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
1033*4882a593Smuzhiyun }
1034*4882a593Smuzhiyun 
mv88e6xxx_g2_irq_bus_lock(struct irq_data * d)1035*4882a593Smuzhiyun static void mv88e6xxx_g2_irq_bus_lock(struct irq_data *d)
1036*4882a593Smuzhiyun {
1037*4882a593Smuzhiyun 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 	mv88e6xxx_reg_lock(chip);
1040*4882a593Smuzhiyun }
1041*4882a593Smuzhiyun 
mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data * d)1042*4882a593Smuzhiyun static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d)
1043*4882a593Smuzhiyun {
1044*4882a593Smuzhiyun 	struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
1045*4882a593Smuzhiyun 	int err;
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun 	err = mv88e6xxx_g2_int_mask(chip, ~chip->g2_irq.masked);
1048*4882a593Smuzhiyun 	if (err)
1049*4882a593Smuzhiyun 		dev_err(chip->dev, "failed to mask interrupts\n");
1050*4882a593Smuzhiyun 
1051*4882a593Smuzhiyun 	mv88e6xxx_reg_unlock(chip);
1052*4882a593Smuzhiyun }
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun static const struct irq_chip mv88e6xxx_g2_irq_chip = {
1055*4882a593Smuzhiyun 	.name			= "mv88e6xxx-g2",
1056*4882a593Smuzhiyun 	.irq_mask		= mv88e6xxx_g2_irq_mask,
1057*4882a593Smuzhiyun 	.irq_unmask		= mv88e6xxx_g2_irq_unmask,
1058*4882a593Smuzhiyun 	.irq_bus_lock		= mv88e6xxx_g2_irq_bus_lock,
1059*4882a593Smuzhiyun 	.irq_bus_sync_unlock	= mv88e6xxx_g2_irq_bus_sync_unlock,
1060*4882a593Smuzhiyun };
1061*4882a593Smuzhiyun 
mv88e6xxx_g2_irq_domain_map(struct irq_domain * d,unsigned int irq,irq_hw_number_t hwirq)1062*4882a593Smuzhiyun static int mv88e6xxx_g2_irq_domain_map(struct irq_domain *d,
1063*4882a593Smuzhiyun 				       unsigned int irq,
1064*4882a593Smuzhiyun 				       irq_hw_number_t hwirq)
1065*4882a593Smuzhiyun {
1066*4882a593Smuzhiyun 	struct mv88e6xxx_chip *chip = d->host_data;
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 	irq_set_chip_data(irq, d->host_data);
1069*4882a593Smuzhiyun 	irq_set_chip_and_handler(irq, &chip->g2_irq.chip, handle_level_irq);
1070*4882a593Smuzhiyun 	irq_set_noprobe(irq);
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun 	return 0;
1073*4882a593Smuzhiyun }
1074*4882a593Smuzhiyun 
1075*4882a593Smuzhiyun static const struct irq_domain_ops mv88e6xxx_g2_irq_domain_ops = {
1076*4882a593Smuzhiyun 	.map	= mv88e6xxx_g2_irq_domain_map,
1077*4882a593Smuzhiyun 	.xlate	= irq_domain_xlate_twocell,
1078*4882a593Smuzhiyun };
1079*4882a593Smuzhiyun 
mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip * chip)1080*4882a593Smuzhiyun void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip)
1081*4882a593Smuzhiyun {
1082*4882a593Smuzhiyun 	int irq, virq;
1083*4882a593Smuzhiyun 
1084*4882a593Smuzhiyun 	mv88e6xxx_g2_watchdog_free(chip);
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun 	free_irq(chip->device_irq, chip);
1087*4882a593Smuzhiyun 	irq_dispose_mapping(chip->device_irq);
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun 	for (irq = 0; irq < 16; irq++) {
1090*4882a593Smuzhiyun 		virq = irq_find_mapping(chip->g2_irq.domain, irq);
1091*4882a593Smuzhiyun 		irq_dispose_mapping(virq);
1092*4882a593Smuzhiyun 	}
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun 	irq_domain_remove(chip->g2_irq.domain);
1095*4882a593Smuzhiyun }
1096*4882a593Smuzhiyun 
mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip * chip)1097*4882a593Smuzhiyun int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip)
1098*4882a593Smuzhiyun {
1099*4882a593Smuzhiyun 	int err, irq, virq;
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun 	chip->g2_irq.masked = ~0;
1102*4882a593Smuzhiyun 	mv88e6xxx_reg_lock(chip);
1103*4882a593Smuzhiyun 	err = mv88e6xxx_g2_int_mask(chip, ~chip->g2_irq.masked);
1104*4882a593Smuzhiyun 	mv88e6xxx_reg_unlock(chip);
1105*4882a593Smuzhiyun 	if (err)
1106*4882a593Smuzhiyun 		return err;
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 	chip->g2_irq.domain = irq_domain_add_simple(
1109*4882a593Smuzhiyun 		chip->dev->of_node, 16, 0, &mv88e6xxx_g2_irq_domain_ops, chip);
1110*4882a593Smuzhiyun 	if (!chip->g2_irq.domain)
1111*4882a593Smuzhiyun 		return -ENOMEM;
1112*4882a593Smuzhiyun 
1113*4882a593Smuzhiyun 	for (irq = 0; irq < 16; irq++)
1114*4882a593Smuzhiyun 		irq_create_mapping(chip->g2_irq.domain, irq);
1115*4882a593Smuzhiyun 
1116*4882a593Smuzhiyun 	chip->g2_irq.chip = mv88e6xxx_g2_irq_chip;
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 	chip->device_irq = irq_find_mapping(chip->g1_irq.domain,
1119*4882a593Smuzhiyun 					    MV88E6XXX_G1_STS_IRQ_DEVICE);
1120*4882a593Smuzhiyun 	if (chip->device_irq < 0) {
1121*4882a593Smuzhiyun 		err = chip->device_irq;
1122*4882a593Smuzhiyun 		goto out;
1123*4882a593Smuzhiyun 	}
1124*4882a593Smuzhiyun 
1125*4882a593Smuzhiyun 	snprintf(chip->device_irq_name, sizeof(chip->device_irq_name),
1126*4882a593Smuzhiyun 		 "mv88e6xxx-%s-g2", dev_name(chip->dev));
1127*4882a593Smuzhiyun 
1128*4882a593Smuzhiyun 	err = request_threaded_irq(chip->device_irq, NULL,
1129*4882a593Smuzhiyun 				   mv88e6xxx_g2_irq_thread_fn,
1130*4882a593Smuzhiyun 				   IRQF_ONESHOT, chip->device_irq_name, chip);
1131*4882a593Smuzhiyun 	if (err)
1132*4882a593Smuzhiyun 		goto out;
1133*4882a593Smuzhiyun 
1134*4882a593Smuzhiyun 	return mv88e6xxx_g2_watchdog_setup(chip);
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun out:
1137*4882a593Smuzhiyun 	for (irq = 0; irq < 16; irq++) {
1138*4882a593Smuzhiyun 		virq = irq_find_mapping(chip->g2_irq.domain, irq);
1139*4882a593Smuzhiyun 		irq_dispose_mapping(virq);
1140*4882a593Smuzhiyun 	}
1141*4882a593Smuzhiyun 
1142*4882a593Smuzhiyun 	irq_domain_remove(chip->g2_irq.domain);
1143*4882a593Smuzhiyun 
1144*4882a593Smuzhiyun 	return err;
1145*4882a593Smuzhiyun }
1146*4882a593Smuzhiyun 
mv88e6xxx_g2_irq_mdio_setup(struct mv88e6xxx_chip * chip,struct mii_bus * bus)1147*4882a593Smuzhiyun int mv88e6xxx_g2_irq_mdio_setup(struct mv88e6xxx_chip *chip,
1148*4882a593Smuzhiyun 				struct mii_bus *bus)
1149*4882a593Smuzhiyun {
1150*4882a593Smuzhiyun 	int phy, irq, err, err_phy;
1151*4882a593Smuzhiyun 
1152*4882a593Smuzhiyun 	for (phy = 0; phy < chip->info->num_internal_phys; phy++) {
1153*4882a593Smuzhiyun 		irq = irq_find_mapping(chip->g2_irq.domain, phy);
1154*4882a593Smuzhiyun 		if (irq < 0) {
1155*4882a593Smuzhiyun 			err = irq;
1156*4882a593Smuzhiyun 			goto out;
1157*4882a593Smuzhiyun 		}
1158*4882a593Smuzhiyun 		bus->irq[chip->info->phy_base_addr + phy] = irq;
1159*4882a593Smuzhiyun 	}
1160*4882a593Smuzhiyun 	return 0;
1161*4882a593Smuzhiyun out:
1162*4882a593Smuzhiyun 	err_phy = phy;
1163*4882a593Smuzhiyun 
1164*4882a593Smuzhiyun 	for (phy = 0; phy < err_phy; phy++)
1165*4882a593Smuzhiyun 		irq_dispose_mapping(bus->irq[phy]);
1166*4882a593Smuzhiyun 
1167*4882a593Smuzhiyun 	return err;
1168*4882a593Smuzhiyun }
1169*4882a593Smuzhiyun 
mv88e6xxx_g2_irq_mdio_free(struct mv88e6xxx_chip * chip,struct mii_bus * bus)1170*4882a593Smuzhiyun void mv88e6xxx_g2_irq_mdio_free(struct mv88e6xxx_chip *chip,
1171*4882a593Smuzhiyun 				struct mii_bus *bus)
1172*4882a593Smuzhiyun {
1173*4882a593Smuzhiyun 	int phy;
1174*4882a593Smuzhiyun 
1175*4882a593Smuzhiyun 	for (phy = 0; phy < chip->info->num_internal_phys; phy++)
1176*4882a593Smuzhiyun 		irq_dispose_mapping(bus->irq[phy]);
1177*4882a593Smuzhiyun }
1178