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, ®);
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, ®);
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, ®);
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, ®);
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, ®);
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, ®);
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