12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2ec561276SVivien Didelot /*
31d90016dSVivien Didelot * Marvell 88E6xxx Switch Global 2 Registers support
4ec561276SVivien Didelot *
5ec561276SVivien Didelot * Copyright (c) 2008 Marvell Semiconductor
6ec561276SVivien Didelot *
74333d619SVivien Didelot * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
84333d619SVivien Didelot * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
9ec561276SVivien Didelot */
10ec561276SVivien Didelot
11e289ef0dSVivien Didelot #include <linux/bitfield.h>
12282ccf6eSFlorian Westphal #include <linux/interrupt.h>
13dc30c35bSAndrew Lunn #include <linux/irqdomain.h>
144d5f2ba7SVivien Didelot
154d5f2ba7SVivien Didelot #include "chip.h"
1682466921SVivien Didelot #include "global1.h" /* for MV88E6XXX_G1_STS_IRQ_DEVICE */
17ec561276SVivien Didelot #include "global2.h"
18ec561276SVivien Didelot
mv88e6xxx_g2_read(struct mv88e6xxx_chip * chip,int reg,u16 * val)19b000be95SBrandon Streiff int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
209fe850fbSVivien Didelot {
219069c13aSVivien Didelot return mv88e6xxx_read(chip, chip->info->global2_addr, reg, val);
229fe850fbSVivien Didelot }
239fe850fbSVivien Didelot
mv88e6xxx_g2_write(struct mv88e6xxx_chip * chip,int reg,u16 val)24b000be95SBrandon Streiff int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
259fe850fbSVivien Didelot {
269069c13aSVivien Didelot return mv88e6xxx_write(chip, chip->info->global2_addr, reg, val);
279fe850fbSVivien Didelot }
289fe850fbSVivien Didelot
mv88e6xxx_g2_wait_bit(struct mv88e6xxx_chip * chip,int reg,int bit,int val)2919fb7f69SVivien Didelot int mv88e6xxx_g2_wait_bit(struct mv88e6xxx_chip *chip, int reg, int
3019fb7f69SVivien Didelot bit, int val)
3119fb7f69SVivien Didelot {
3219fb7f69SVivien Didelot return mv88e6xxx_wait_bit(chip, chip->info->global2_addr, reg,
3319fb7f69SVivien Didelot bit, val);
3419fb7f69SVivien Didelot }
3519fb7f69SVivien Didelot
36d6c5e6afSVivien Didelot /* Offset 0x00: Interrupt Source Register */
37d6c5e6afSVivien Didelot
mv88e6xxx_g2_int_source(struct mv88e6xxx_chip * chip,u16 * src)38d6c5e6afSVivien Didelot static int mv88e6xxx_g2_int_source(struct mv88e6xxx_chip *chip, u16 *src)
39d6c5e6afSVivien Didelot {
40d6c5e6afSVivien Didelot /* Read (and clear most of) the Interrupt Source bits */
41d6c5e6afSVivien Didelot return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_INT_SRC, src);
42d6c5e6afSVivien Didelot }
43d6c5e6afSVivien Didelot
44d6c5e6afSVivien Didelot /* Offset 0x01: Interrupt Mask Register */
45d6c5e6afSVivien Didelot
mv88e6xxx_g2_int_mask(struct mv88e6xxx_chip * chip,u16 mask)46d6c5e6afSVivien Didelot static int mv88e6xxx_g2_int_mask(struct mv88e6xxx_chip *chip, u16 mask)
47d6c5e6afSVivien Didelot {
48d6c5e6afSVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_INT_MASK, mask);
49d6c5e6afSVivien Didelot }
50d6c5e6afSVivien Didelot
516e55f698SAndrew Lunn /* Offset 0x02: Management Enable 2x */
5251c901a7SVivien Didelot
mv88e6xxx_g2_mgmt_enable_2x(struct mv88e6xxx_chip * chip,u16 en2x)5351c901a7SVivien Didelot static int mv88e6xxx_g2_mgmt_enable_2x(struct mv88e6xxx_chip *chip, u16 en2x)
5451c901a7SVivien Didelot {
5551c901a7SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_2X, en2x);
5651c901a7SVivien Didelot }
5751c901a7SVivien Didelot
586e55f698SAndrew Lunn /* Offset 0x03: Management Enable 0x */
596e55f698SAndrew Lunn
mv88e6xxx_g2_mgmt_enable_0x(struct mv88e6xxx_chip * chip,u16 en0x)6051c901a7SVivien Didelot static int mv88e6xxx_g2_mgmt_enable_0x(struct mv88e6xxx_chip *chip, u16 en0x)
6151c901a7SVivien Didelot {
6251c901a7SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_0X, en0x);
6351c901a7SVivien Didelot }
6451c901a7SVivien Didelot
6551c901a7SVivien Didelot /* Offset 0x05: Switch Management Register */
6651c901a7SVivien Didelot
mv88e6xxx_g2_switch_mgmt_rsvd2cpu(struct mv88e6xxx_chip * chip,bool enable)6751c901a7SVivien Didelot static int mv88e6xxx_g2_switch_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip,
6851c901a7SVivien Didelot bool enable)
6951c901a7SVivien Didelot {
7051c901a7SVivien Didelot u16 val;
7151c901a7SVivien Didelot int err;
7251c901a7SVivien Didelot
7351c901a7SVivien Didelot err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SWITCH_MGMT, &val);
7451c901a7SVivien Didelot if (err)
7551c901a7SVivien Didelot return err;
7651c901a7SVivien Didelot
7751c901a7SVivien Didelot if (enable)
7851c901a7SVivien Didelot val |= MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU;
7951c901a7SVivien Didelot else
8051c901a7SVivien Didelot val &= ~MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU;
8151c901a7SVivien Didelot
8251c901a7SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MGMT, val);
8351c901a7SVivien Didelot }
8451c901a7SVivien Didelot
mv88e6185_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip * chip)8551c901a7SVivien Didelot int mv88e6185_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
8651c901a7SVivien Didelot {
8751c901a7SVivien Didelot int err;
8851c901a7SVivien Didelot
8951c901a7SVivien Didelot /* Consider the frames with reserved multicast destination
9051c901a7SVivien Didelot * addresses matching 01:80:c2:00:00:0x as MGMT.
9151c901a7SVivien Didelot */
9251c901a7SVivien Didelot err = mv88e6xxx_g2_mgmt_enable_0x(chip, 0xffff);
9351c901a7SVivien Didelot if (err)
9451c901a7SVivien Didelot return err;
9551c901a7SVivien Didelot
9651c901a7SVivien Didelot return mv88e6xxx_g2_switch_mgmt_rsvd2cpu(chip, true);
9751c901a7SVivien Didelot }
9851c901a7SVivien Didelot
mv88e6352_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip * chip)9951c901a7SVivien Didelot int mv88e6352_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
1006e55f698SAndrew Lunn {
1016e55f698SAndrew Lunn int err;
1026e55f698SAndrew Lunn
1036e55f698SAndrew Lunn /* Consider the frames with reserved multicast destination
1046e55f698SAndrew Lunn * addresses matching 01:80:c2:00:00:2x as MGMT.
1056e55f698SAndrew Lunn */
10651c901a7SVivien Didelot err = mv88e6xxx_g2_mgmt_enable_2x(chip, 0xffff);
1076e55f698SAndrew Lunn if (err)
1086e55f698SAndrew Lunn return err;
1096e55f698SAndrew Lunn
11051c901a7SVivien Didelot return mv88e6185_g2_mgmt_rsvd2cpu(chip);
1116e55f698SAndrew Lunn }
1126e55f698SAndrew Lunn
113ec561276SVivien Didelot /* Offset 0x06: Device Mapping Table register */
114ec561276SVivien Didelot
mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip * chip,int target,int port)115c7f047b6SVivien Didelot int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target,
116c7f047b6SVivien Didelot int port)
117ec561276SVivien Didelot {
118c7f047b6SVivien Didelot u16 val = (target << 8) | (port & 0x1f);
119c7f047b6SVivien Didelot /* Modern chips use 5 bits to define a device mapping port,
120c7f047b6SVivien Didelot * but bit 4 is reserved on older chips, so it is safe to use.
121c7f047b6SVivien Didelot */
122ec561276SVivien Didelot
1232ad4da77SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_DEVICE_MAPPING,
1242ad4da77SVivien Didelot MV88E6XXX_G2_DEVICE_MAPPING_UPDATE | val);
125ec561276SVivien Didelot }
126ec561276SVivien Didelot
127ec561276SVivien Didelot /* Offset 0x07: Trunk Mask Table register */
128ec561276SVivien Didelot
mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip * chip,int num,bool hash,u16 mask)12957e661aaSTobias Waldekranz int mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip *chip, int num,
13056dc7347SVivien Didelot bool hash, u16 mask)
131ec561276SVivien Didelot {
13256dc7347SVivien Didelot u16 val = (num << 12) | (mask & mv88e6xxx_port_mask(chip));
133ec561276SVivien Didelot
13456dc7347SVivien Didelot if (hash)
13556dc7347SVivien Didelot val |= MV88E6XXX_G2_TRUNK_MASK_HASH;
136ec561276SVivien Didelot
1372ad4da77SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_TRUNK_MASK,
1382ad4da77SVivien Didelot MV88E6XXX_G2_TRUNK_MASK_UPDATE | val);
139ec561276SVivien Didelot }
140ec561276SVivien Didelot
141ec561276SVivien Didelot /* Offset 0x08: Trunk Mapping Table register */
142ec561276SVivien Didelot
mv88e6xxx_g2_trunk_mapping_write(struct mv88e6xxx_chip * chip,int id,u16 map)14357e661aaSTobias Waldekranz int mv88e6xxx_g2_trunk_mapping_write(struct mv88e6xxx_chip *chip, int id,
144ec561276SVivien Didelot u16 map)
145ec561276SVivien Didelot {
146370b4ffbSVivien Didelot const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
147ec561276SVivien Didelot u16 val = (id << 11) | (map & port_mask);
148ec561276SVivien Didelot
1492ad4da77SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_TRUNK_MAPPING,
1502ad4da77SVivien Didelot MV88E6XXX_G2_TRUNK_MAPPING_UPDATE | val);
151ec561276SVivien Didelot }
152ec561276SVivien Didelot
mv88e6xxx_g2_trunk_clear(struct mv88e6xxx_chip * chip)153b28f872dSVivien Didelot int mv88e6xxx_g2_trunk_clear(struct mv88e6xxx_chip *chip)
154ec561276SVivien Didelot {
155370b4ffbSVivien Didelot const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1;
156ec561276SVivien Didelot int i, err;
157ec561276SVivien Didelot
158ec561276SVivien Didelot /* Clear all eight possible Trunk Mask vectors */
159ec561276SVivien Didelot for (i = 0; i < 8; ++i) {
160ec561276SVivien Didelot err = mv88e6xxx_g2_trunk_mask_write(chip, i, false, port_mask);
161ec561276SVivien Didelot if (err)
162ec561276SVivien Didelot return err;
163ec561276SVivien Didelot }
164ec561276SVivien Didelot
165ec561276SVivien Didelot /* Clear all sixteen possible Trunk ID routing vectors */
166ec561276SVivien Didelot for (i = 0; i < 16; ++i) {
167ec561276SVivien Didelot err = mv88e6xxx_g2_trunk_mapping_write(chip, i, 0);
168ec561276SVivien Didelot if (err)
169ec561276SVivien Didelot return err;
170ec561276SVivien Didelot }
171ec561276SVivien Didelot
172ec561276SVivien Didelot return 0;
173ec561276SVivien Didelot }
174ec561276SVivien Didelot
175ec561276SVivien Didelot /* Offset 0x09: Ingress Rate Command register
176ec561276SVivien Didelot * Offset 0x0A: Ingress Rate Data register
177ec561276SVivien Didelot */
178ec561276SVivien Didelot
mv88e6xxx_g2_irl_wait(struct mv88e6xxx_chip * chip)179cd8da8bbSVivien Didelot static int mv88e6xxx_g2_irl_wait(struct mv88e6xxx_chip *chip)
180ec561276SVivien Didelot {
18119fb7f69SVivien Didelot int bit = __bf_shf(MV88E6XXX_G2_IRL_CMD_BUSY);
18219fb7f69SVivien Didelot
18319fb7f69SVivien Didelot return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_IRL_CMD, bit, 0);
184ec561276SVivien Didelot }
185ec561276SVivien Didelot
mv88e6xxx_g2_irl_op(struct mv88e6xxx_chip * chip,u16 op,int port,int res,int reg)186cd8da8bbSVivien Didelot static int mv88e6xxx_g2_irl_op(struct mv88e6xxx_chip *chip, u16 op, int port,
187cd8da8bbSVivien Didelot int res, int reg)
188cd8da8bbSVivien Didelot {
189cd8da8bbSVivien Didelot int err;
190cd8da8bbSVivien Didelot
191cd8da8bbSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_IRL_CMD,
192cd8da8bbSVivien Didelot MV88E6XXX_G2_IRL_CMD_BUSY | op | (port << 8) |
193cd8da8bbSVivien Didelot (res << 5) | reg);
194cd8da8bbSVivien Didelot if (err)
195ec561276SVivien Didelot return err;
196cd8da8bbSVivien Didelot
197cd8da8bbSVivien Didelot return mv88e6xxx_g2_irl_wait(chip);
198cd8da8bbSVivien Didelot }
199cd8da8bbSVivien Didelot
mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip * chip,int port)200cd8da8bbSVivien Didelot int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
201cd8da8bbSVivien Didelot {
202cd8da8bbSVivien Didelot return mv88e6xxx_g2_irl_op(chip, MV88E6352_G2_IRL_CMD_OP_INIT_ALL, port,
203cd8da8bbSVivien Didelot 0, 0);
204cd8da8bbSVivien Didelot }
205cd8da8bbSVivien Didelot
mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip * chip,int port)206cd8da8bbSVivien Didelot int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
207cd8da8bbSVivien Didelot {
208cd8da8bbSVivien Didelot return mv88e6xxx_g2_irl_op(chip, MV88E6390_G2_IRL_CMD_OP_INIT_ALL, port,
209cd8da8bbSVivien Didelot 0, 0);
210ec561276SVivien Didelot }
211ec561276SVivien Didelot
21217a1594eSVivien Didelot /* Offset 0x0B: Cross-chip Port VLAN (Addr) Register
21317a1594eSVivien Didelot * Offset 0x0C: Cross-chip Port VLAN Data Register
21417a1594eSVivien Didelot */
21517a1594eSVivien Didelot
mv88e6xxx_g2_pvt_op_wait(struct mv88e6xxx_chip * chip)21617a1594eSVivien Didelot static int mv88e6xxx_g2_pvt_op_wait(struct mv88e6xxx_chip *chip)
21717a1594eSVivien Didelot {
21819fb7f69SVivien Didelot int bit = __bf_shf(MV88E6XXX_G2_PVT_ADDR_BUSY);
21919fb7f69SVivien Didelot
22019fb7f69SVivien Didelot return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_PVT_ADDR, bit, 0);
22117a1594eSVivien Didelot }
22217a1594eSVivien Didelot
mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip * chip,int src_dev,int src_port,u16 op)22317a1594eSVivien Didelot static int mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip *chip, int src_dev,
22417a1594eSVivien Didelot int src_port, u16 op)
22517a1594eSVivien Didelot {
22617a1594eSVivien Didelot int err;
22717a1594eSVivien Didelot
22867d1ea8eSVivien Didelot /* 9-bit Cross-chip PVT pointer: with MV88E6XXX_G2_MISC_5_BIT_PORT
22967d1ea8eSVivien Didelot * cleared, source device is 5-bit, source port is 4-bit.
23017a1594eSVivien Didelot */
23167d1ea8eSVivien Didelot op |= MV88E6XXX_G2_PVT_ADDR_BUSY;
23217a1594eSVivien Didelot op |= (src_dev & 0x1f) << 4;
23317a1594eSVivien Didelot op |= (src_port & 0xf);
23417a1594eSVivien Didelot
23567d1ea8eSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_ADDR, op);
23617a1594eSVivien Didelot if (err)
23717a1594eSVivien Didelot return err;
23817a1594eSVivien Didelot
23917a1594eSVivien Didelot return mv88e6xxx_g2_pvt_op_wait(chip);
24017a1594eSVivien Didelot }
24117a1594eSVivien Didelot
mv88e6xxx_g2_pvt_read(struct mv88e6xxx_chip * chip,int src_dev,int src_port,u16 * data)242836021a2STobias Waldekranz int mv88e6xxx_g2_pvt_read(struct mv88e6xxx_chip *chip, int src_dev,
243836021a2STobias Waldekranz int src_port, u16 *data)
244836021a2STobias Waldekranz {
245836021a2STobias Waldekranz int err;
246836021a2STobias Waldekranz
247836021a2STobias Waldekranz err = mv88e6xxx_g2_pvt_op_wait(chip);
248836021a2STobias Waldekranz if (err)
249836021a2STobias Waldekranz return err;
250836021a2STobias Waldekranz
251836021a2STobias Waldekranz err = mv88e6xxx_g2_pvt_op(chip, src_dev, src_port,
252836021a2STobias Waldekranz MV88E6XXX_G2_PVT_ADDR_OP_READ);
253836021a2STobias Waldekranz if (err)
254836021a2STobias Waldekranz return err;
255836021a2STobias Waldekranz
256836021a2STobias Waldekranz return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_PVT_DATA, data);
257836021a2STobias Waldekranz }
258836021a2STobias Waldekranz
mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip * chip,int src_dev,int src_port,u16 data)25917a1594eSVivien Didelot int mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev,
26017a1594eSVivien Didelot int src_port, u16 data)
26117a1594eSVivien Didelot {
26217a1594eSVivien Didelot int err;
26317a1594eSVivien Didelot
26417a1594eSVivien Didelot err = mv88e6xxx_g2_pvt_op_wait(chip);
26517a1594eSVivien Didelot if (err)
26617a1594eSVivien Didelot return err;
26717a1594eSVivien Didelot
26867d1ea8eSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_DATA, data);
26917a1594eSVivien Didelot if (err)
27017a1594eSVivien Didelot return err;
27117a1594eSVivien Didelot
27217a1594eSVivien Didelot return mv88e6xxx_g2_pvt_op(chip, src_dev, src_port,
27367d1ea8eSVivien Didelot MV88E6XXX_G2_PVT_ADDR_OP_WRITE_PVLAN);
27417a1594eSVivien Didelot }
27517a1594eSVivien Didelot
276ec561276SVivien Didelot /* Offset 0x0D: Switch MAC/WoL/WoF register */
277ec561276SVivien Didelot
mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip * chip,unsigned int pointer,u8 data)278ec561276SVivien Didelot static int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip,
279ec561276SVivien Didelot unsigned int pointer, u8 data)
280ec561276SVivien Didelot {
281ec561276SVivien Didelot u16 val = (pointer << 8) | data;
282ec561276SVivien Didelot
2832ad4da77SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MAC,
2842ad4da77SVivien Didelot MV88E6XXX_G2_SWITCH_MAC_UPDATE | val);
285ec561276SVivien Didelot }
286ec561276SVivien Didelot
mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip * chip,u8 * addr)287ec561276SVivien Didelot int mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr)
288ec561276SVivien Didelot {
289ec561276SVivien Didelot int i, err;
290ec561276SVivien Didelot
291ec561276SVivien Didelot for (i = 0; i < 6; i++) {
292ec561276SVivien Didelot err = mv88e6xxx_g2_switch_mac_write(chip, i, addr[i]);
293ec561276SVivien Didelot if (err)
294ec561276SVivien Didelot break;
295ec561276SVivien Didelot }
296ec561276SVivien Didelot
297ec561276SVivien Didelot return err;
298ec561276SVivien Didelot }
299ec561276SVivien Didelot
3006239a386SAndrew Lunn /* Offset 0x0E: ATU Statistics */
3016239a386SAndrew Lunn
mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip * chip,u16 kind,u16 bin)3026239a386SAndrew Lunn int mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip *chip, u16 kind, u16 bin)
3036239a386SAndrew Lunn {
3046239a386SAndrew Lunn return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_ATU_STATS,
3056239a386SAndrew Lunn kind | bin);
3066239a386SAndrew Lunn }
3076239a386SAndrew Lunn
mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip * chip,u16 * stats)308c5f299d5SAndrew Lunn int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip, u16 *stats)
3096239a386SAndrew Lunn {
310c5f299d5SAndrew Lunn return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_ATU_STATS, stats);
3116239a386SAndrew Lunn }
3126239a386SAndrew Lunn
313ec561276SVivien Didelot /* Offset 0x0F: Priority Override Table */
314ec561276SVivien Didelot
mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip * chip,int pointer,u8 data)315ec561276SVivien Didelot static int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer,
316ec561276SVivien Didelot u8 data)
317ec561276SVivien Didelot {
318ec561276SVivien Didelot u16 val = (pointer << 8) | (data & 0x7);
319ec561276SVivien Didelot
3202ad4da77SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PRIO_OVERRIDE,
3212ad4da77SVivien Didelot MV88E6XXX_G2_PRIO_OVERRIDE_UPDATE | val);
322ec561276SVivien Didelot }
323ec561276SVivien Didelot
mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip * chip)3249e907d73SVivien Didelot int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip)
325ec561276SVivien Didelot {
326ec561276SVivien Didelot int i, err;
327ec561276SVivien Didelot
328ec561276SVivien Didelot /* Clear all sixteen possible Priority Override entries */
329ec561276SVivien Didelot for (i = 0; i < 16; i++) {
330ec561276SVivien Didelot err = mv88e6xxx_g2_pot_write(chip, i, 0);
331ec561276SVivien Didelot if (err)
332ec561276SVivien Didelot break;
333ec561276SVivien Didelot }
334ec561276SVivien Didelot
335ec561276SVivien Didelot return err;
336ec561276SVivien Didelot }
337ec561276SVivien Didelot
338ec561276SVivien Didelot /* Offset 0x14: EEPROM Command
33998fc3c6fSVivien Didelot * Offset 0x15: EEPROM Data (for 16-bit data access)
34098fc3c6fSVivien Didelot * Offset 0x15: EEPROM Addr (for 8-bit data access)
341ec561276SVivien Didelot */
342ec561276SVivien Didelot
mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip * chip)343*6ccf50d4SFabio Estevam int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
344ec561276SVivien Didelot {
34519fb7f69SVivien Didelot int bit = __bf_shf(MV88E6XXX_G2_EEPROM_CMD_BUSY);
34619fb7f69SVivien Didelot int err;
34719fb7f69SVivien Didelot
34819fb7f69SVivien Didelot err = mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_EEPROM_CMD, bit, 0);
34919fb7f69SVivien Didelot if (err)
35019fb7f69SVivien Didelot return err;
35119fb7f69SVivien Didelot
35219fb7f69SVivien Didelot bit = __bf_shf(MV88E6XXX_G2_EEPROM_CMD_RUNNING);
35319fb7f69SVivien Didelot
35419fb7f69SVivien Didelot return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_EEPROM_CMD, bit, 0);
355ec561276SVivien Didelot }
356ec561276SVivien Didelot
mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip * chip,u16 cmd)357ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
358ec561276SVivien Didelot {
359ec561276SVivien Didelot int err;
360ec561276SVivien Didelot
3617fc8c9d5SVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_EEPROM_CMD,
3627fc8c9d5SVivien Didelot MV88E6XXX_G2_EEPROM_CMD_BUSY | cmd);
363ec561276SVivien Didelot if (err)
364ec561276SVivien Didelot return err;
365ec561276SVivien Didelot
366ec561276SVivien Didelot return mv88e6xxx_g2_eeprom_wait(chip);
367ec561276SVivien Didelot }
368ec561276SVivien Didelot
mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip * chip,u16 addr,u8 * data)36998fc3c6fSVivien Didelot static int mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip *chip,
37098fc3c6fSVivien Didelot u16 addr, u8 *data)
37198fc3c6fSVivien Didelot {
3727fc8c9d5SVivien Didelot u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ;
37398fc3c6fSVivien Didelot int err;
37498fc3c6fSVivien Didelot
37598fc3c6fSVivien Didelot err = mv88e6xxx_g2_eeprom_wait(chip);
37698fc3c6fSVivien Didelot if (err)
37798fc3c6fSVivien Didelot return err;
37898fc3c6fSVivien Didelot
3797fc8c9d5SVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr);
38098fc3c6fSVivien Didelot if (err)
38198fc3c6fSVivien Didelot return err;
38298fc3c6fSVivien Didelot
38398fc3c6fSVivien Didelot err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
38498fc3c6fSVivien Didelot if (err)
38598fc3c6fSVivien Didelot return err;
38698fc3c6fSVivien Didelot
3877fc8c9d5SVivien Didelot err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &cmd);
38898fc3c6fSVivien Didelot if (err)
38998fc3c6fSVivien Didelot return err;
39098fc3c6fSVivien Didelot
39198fc3c6fSVivien Didelot *data = cmd & 0xff;
39298fc3c6fSVivien Didelot
39398fc3c6fSVivien Didelot return 0;
39498fc3c6fSVivien Didelot }
39598fc3c6fSVivien Didelot
mv88e6xxx_g2_eeprom_write8(struct mv88e6xxx_chip * chip,u16 addr,u8 data)39698fc3c6fSVivien Didelot static int mv88e6xxx_g2_eeprom_write8(struct mv88e6xxx_chip *chip,
39798fc3c6fSVivien Didelot u16 addr, u8 data)
39898fc3c6fSVivien Didelot {
3997fc8c9d5SVivien Didelot u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE |
4007fc8c9d5SVivien Didelot MV88E6XXX_G2_EEPROM_CMD_WRITE_EN;
40198fc3c6fSVivien Didelot int err;
40298fc3c6fSVivien Didelot
40398fc3c6fSVivien Didelot err = mv88e6xxx_g2_eeprom_wait(chip);
40498fc3c6fSVivien Didelot if (err)
40598fc3c6fSVivien Didelot return err;
40698fc3c6fSVivien Didelot
4077fc8c9d5SVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr);
40898fc3c6fSVivien Didelot if (err)
40998fc3c6fSVivien Didelot return err;
41098fc3c6fSVivien Didelot
41198fc3c6fSVivien Didelot return mv88e6xxx_g2_eeprom_cmd(chip, cmd | data);
41298fc3c6fSVivien Didelot }
41398fc3c6fSVivien Didelot
mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip * chip,u8 addr,u16 * data)414ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip,
415ec561276SVivien Didelot u8 addr, u16 *data)
416ec561276SVivien Didelot {
4177fc8c9d5SVivien Didelot u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ | addr;
418ec561276SVivien Didelot int err;
419ec561276SVivien Didelot
420ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_wait(chip);
421ec561276SVivien Didelot if (err)
422ec561276SVivien Didelot return err;
423ec561276SVivien Didelot
424ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
425ec561276SVivien Didelot if (err)
426ec561276SVivien Didelot return err;
427ec561276SVivien Didelot
4287fc8c9d5SVivien Didelot return mv88e6xxx_g2_read(chip, MV88E6352_G2_EEPROM_DATA, data);
429ec561276SVivien Didelot }
430ec561276SVivien Didelot
mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip * chip,u8 addr,u16 data)431ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip *chip,
432ec561276SVivien Didelot u8 addr, u16 data)
433ec561276SVivien Didelot {
4347fc8c9d5SVivien Didelot u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE | addr;
435ec561276SVivien Didelot int err;
436ec561276SVivien Didelot
437ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_wait(chip);
438ec561276SVivien Didelot if (err)
439ec561276SVivien Didelot return err;
440ec561276SVivien Didelot
4417fc8c9d5SVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6352_G2_EEPROM_DATA, data);
442ec561276SVivien Didelot if (err)
443ec561276SVivien Didelot return err;
444ec561276SVivien Didelot
445ec561276SVivien Didelot return mv88e6xxx_g2_eeprom_cmd(chip, cmd);
446ec561276SVivien Didelot }
447ec561276SVivien Didelot
mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip * chip,struct ethtool_eeprom * eeprom,u8 * data)44898fc3c6fSVivien Didelot int mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip *chip,
44998fc3c6fSVivien Didelot struct ethtool_eeprom *eeprom, u8 *data)
45098fc3c6fSVivien Didelot {
45198fc3c6fSVivien Didelot unsigned int offset = eeprom->offset;
45298fc3c6fSVivien Didelot unsigned int len = eeprom->len;
45398fc3c6fSVivien Didelot int err;
45498fc3c6fSVivien Didelot
45598fc3c6fSVivien Didelot eeprom->len = 0;
45698fc3c6fSVivien Didelot
45798fc3c6fSVivien Didelot while (len) {
45898fc3c6fSVivien Didelot err = mv88e6xxx_g2_eeprom_read8(chip, offset, data);
45998fc3c6fSVivien Didelot if (err)
46098fc3c6fSVivien Didelot return err;
46198fc3c6fSVivien Didelot
46298fc3c6fSVivien Didelot eeprom->len++;
46398fc3c6fSVivien Didelot offset++;
46498fc3c6fSVivien Didelot data++;
46598fc3c6fSVivien Didelot len--;
46698fc3c6fSVivien Didelot }
46798fc3c6fSVivien Didelot
46898fc3c6fSVivien Didelot return 0;
46998fc3c6fSVivien Didelot }
47098fc3c6fSVivien Didelot
mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip * chip,struct ethtool_eeprom * eeprom,u8 * data)47198fc3c6fSVivien Didelot int mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip *chip,
47298fc3c6fSVivien Didelot struct ethtool_eeprom *eeprom, u8 *data)
47398fc3c6fSVivien Didelot {
47498fc3c6fSVivien Didelot unsigned int offset = eeprom->offset;
47598fc3c6fSVivien Didelot unsigned int len = eeprom->len;
47698fc3c6fSVivien Didelot int err;
47798fc3c6fSVivien Didelot
47898fc3c6fSVivien Didelot eeprom->len = 0;
47998fc3c6fSVivien Didelot
48098fc3c6fSVivien Didelot while (len) {
48198fc3c6fSVivien Didelot err = mv88e6xxx_g2_eeprom_write8(chip, offset, *data);
48298fc3c6fSVivien Didelot if (err)
48398fc3c6fSVivien Didelot return err;
48498fc3c6fSVivien Didelot
48598fc3c6fSVivien Didelot eeprom->len++;
48698fc3c6fSVivien Didelot offset++;
48798fc3c6fSVivien Didelot data++;
48898fc3c6fSVivien Didelot len--;
48998fc3c6fSVivien Didelot }
49098fc3c6fSVivien Didelot
49198fc3c6fSVivien Didelot return 0;
49298fc3c6fSVivien Didelot }
49398fc3c6fSVivien Didelot
mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip * chip,struct ethtool_eeprom * eeprom,u8 * data)494ec561276SVivien Didelot int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
495ec561276SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data)
496ec561276SVivien Didelot {
497ec561276SVivien Didelot unsigned int offset = eeprom->offset;
498ec561276SVivien Didelot unsigned int len = eeprom->len;
499ec561276SVivien Didelot u16 val;
500ec561276SVivien Didelot int err;
501ec561276SVivien Didelot
502ec561276SVivien Didelot eeprom->len = 0;
503ec561276SVivien Didelot
504ec561276SVivien Didelot if (offset & 1) {
505ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
506ec561276SVivien Didelot if (err)
507ec561276SVivien Didelot return err;
508ec561276SVivien Didelot
509ec561276SVivien Didelot *data++ = (val >> 8) & 0xff;
510ec561276SVivien Didelot
511ec561276SVivien Didelot offset++;
512ec561276SVivien Didelot len--;
513ec561276SVivien Didelot eeprom->len++;
514ec561276SVivien Didelot }
515ec561276SVivien Didelot
516ec561276SVivien Didelot while (len >= 2) {
517ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
518ec561276SVivien Didelot if (err)
519ec561276SVivien Didelot return err;
520ec561276SVivien Didelot
521ec561276SVivien Didelot *data++ = val & 0xff;
522ec561276SVivien Didelot *data++ = (val >> 8) & 0xff;
523ec561276SVivien Didelot
524ec561276SVivien Didelot offset += 2;
525ec561276SVivien Didelot len -= 2;
526ec561276SVivien Didelot eeprom->len += 2;
527ec561276SVivien Didelot }
528ec561276SVivien Didelot
529ec561276SVivien Didelot if (len) {
530ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
531ec561276SVivien Didelot if (err)
532ec561276SVivien Didelot return err;
533ec561276SVivien Didelot
534ec561276SVivien Didelot *data++ = val & 0xff;
535ec561276SVivien Didelot
536ec561276SVivien Didelot offset++;
537ec561276SVivien Didelot len--;
538ec561276SVivien Didelot eeprom->len++;
539ec561276SVivien Didelot }
540ec561276SVivien Didelot
541ec561276SVivien Didelot return 0;
542ec561276SVivien Didelot }
543ec561276SVivien Didelot
mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip * chip,struct ethtool_eeprom * eeprom,u8 * data)544ec561276SVivien Didelot int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
545ec561276SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data)
546ec561276SVivien Didelot {
547ec561276SVivien Didelot unsigned int offset = eeprom->offset;
548ec561276SVivien Didelot unsigned int len = eeprom->len;
549ec561276SVivien Didelot u16 val;
550ec561276SVivien Didelot int err;
551ec561276SVivien Didelot
552ec561276SVivien Didelot /* Ensure the RO WriteEn bit is set */
5537fc8c9d5SVivien Didelot err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &val);
554ec561276SVivien Didelot if (err)
555ec561276SVivien Didelot return err;
556ec561276SVivien Didelot
5577fc8c9d5SVivien Didelot if (!(val & MV88E6XXX_G2_EEPROM_CMD_WRITE_EN))
558ec561276SVivien Didelot return -EROFS;
559ec561276SVivien Didelot
560ec561276SVivien Didelot eeprom->len = 0;
561ec561276SVivien Didelot
562ec561276SVivien Didelot if (offset & 1) {
563ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
564ec561276SVivien Didelot if (err)
565ec561276SVivien Didelot return err;
566ec561276SVivien Didelot
567ec561276SVivien Didelot val = (*data++ << 8) | (val & 0xff);
568ec561276SVivien Didelot
569ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
570ec561276SVivien Didelot if (err)
571ec561276SVivien Didelot return err;
572ec561276SVivien Didelot
573ec561276SVivien Didelot offset++;
574ec561276SVivien Didelot len--;
575ec561276SVivien Didelot eeprom->len++;
576ec561276SVivien Didelot }
577ec561276SVivien Didelot
578ec561276SVivien Didelot while (len >= 2) {
579ec561276SVivien Didelot val = *data++;
580ec561276SVivien Didelot val |= *data++ << 8;
581ec561276SVivien Didelot
582ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
583ec561276SVivien Didelot if (err)
584ec561276SVivien Didelot return err;
585ec561276SVivien Didelot
586ec561276SVivien Didelot offset += 2;
587ec561276SVivien Didelot len -= 2;
588ec561276SVivien Didelot eeprom->len += 2;
589ec561276SVivien Didelot }
590ec561276SVivien Didelot
591ec561276SVivien Didelot if (len) {
592ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
593ec561276SVivien Didelot if (err)
594ec561276SVivien Didelot return err;
595ec561276SVivien Didelot
596ec561276SVivien Didelot val = (val & 0xff00) | *data++;
597ec561276SVivien Didelot
598ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
599ec561276SVivien Didelot if (err)
600ec561276SVivien Didelot return err;
601ec561276SVivien Didelot
602ec561276SVivien Didelot offset++;
603ec561276SVivien Didelot len--;
604ec561276SVivien Didelot eeprom->len++;
605ec561276SVivien Didelot }
606ec561276SVivien Didelot
607ec561276SVivien Didelot return 0;
608ec561276SVivien Didelot }
609ec561276SVivien Didelot
610ec561276SVivien Didelot /* Offset 0x18: SMI PHY Command Register
611ec561276SVivien Didelot * Offset 0x19: SMI PHY Data Register
612ec561276SVivien Didelot */
613ec561276SVivien Didelot
mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip * chip)614ec561276SVivien Didelot static int mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip *chip)
615ec561276SVivien Didelot {
61619fb7f69SVivien Didelot int bit = __bf_shf(MV88E6XXX_G2_SMI_PHY_CMD_BUSY);
61719fb7f69SVivien Didelot
61819fb7f69SVivien Didelot return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_SMI_PHY_CMD, bit, 0);
619ec561276SVivien Didelot }
620ec561276SVivien Didelot
mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip * chip,u16 cmd)621ec561276SVivien Didelot static int mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
622ec561276SVivien Didelot {
623ec561276SVivien Didelot int err;
624ec561276SVivien Didelot
625e289ef0dSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_CMD,
626e289ef0dSVivien Didelot MV88E6XXX_G2_SMI_PHY_CMD_BUSY | cmd);
627ec561276SVivien Didelot if (err)
628ec561276SVivien Didelot return err;
629ec561276SVivien Didelot
630ec561276SVivien Didelot return mv88e6xxx_g2_smi_phy_wait(chip);
631ec561276SVivien Didelot }
632ec561276SVivien Didelot
mv88e6xxx_g2_smi_phy_access(struct mv88e6xxx_chip * chip,bool external,bool c45,u16 op,int dev,int reg)633e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_access(struct mv88e6xxx_chip *chip,
634e289ef0dSVivien Didelot bool external, bool c45, u16 op, int dev,
635e289ef0dSVivien Didelot int reg)
636ec561276SVivien Didelot {
637e289ef0dSVivien Didelot u16 cmd = op;
638ec561276SVivien Didelot
639cf3e80dfSAndrew Lunn if (external)
640e289ef0dSVivien Didelot cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_EXTERNAL;
641e289ef0dSVivien Didelot else
642e289ef0dSVivien Didelot cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_INTERNAL; /* empty mask */
643cf3e80dfSAndrew Lunn
644e289ef0dSVivien Didelot if (c45)
645e289ef0dSVivien Didelot cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_45; /* empty mask */
646e289ef0dSVivien Didelot else
647e289ef0dSVivien Didelot cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_22;
648cf3e80dfSAndrew Lunn
649e289ef0dSVivien Didelot dev <<= __bf_shf(MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK);
650e289ef0dSVivien Didelot cmd |= dev & MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK;
651e289ef0dSVivien Didelot cmd |= reg & MV88E6XXX_G2_SMI_PHY_CMD_REG_ADDR_MASK;
652cf3e80dfSAndrew Lunn
653cf3e80dfSAndrew Lunn return mv88e6xxx_g2_smi_phy_cmd(chip, cmd);
654cf3e80dfSAndrew Lunn }
655cf3e80dfSAndrew Lunn
mv88e6xxx_g2_smi_phy_access_c22(struct mv88e6xxx_chip * chip,bool external,u16 op,int dev,int reg)656e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_access_c22(struct mv88e6xxx_chip *chip,
657e289ef0dSVivien Didelot bool external, u16 op, int dev,
658e289ef0dSVivien Didelot int reg)
659cf3e80dfSAndrew Lunn {
660e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_access(chip, external, false, op, dev, reg);
661cf3e80dfSAndrew Lunn }
662cf3e80dfSAndrew Lunn
663e289ef0dSVivien Didelot /* 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)664e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_read_data_c22(struct mv88e6xxx_chip *chip,
665e289ef0dSVivien Didelot bool external, int dev, int reg,
666e289ef0dSVivien Didelot u16 *data)
667cf3e80dfSAndrew Lunn {
668e289ef0dSVivien Didelot u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_READ_DATA;
669cf3e80dfSAndrew Lunn int err;
670cf3e80dfSAndrew Lunn
671ec561276SVivien Didelot err = mv88e6xxx_g2_smi_phy_wait(chip);
672ec561276SVivien Didelot if (err)
673ec561276SVivien Didelot return err;
674ec561276SVivien Didelot
675e289ef0dSVivien Didelot err = mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
676ec561276SVivien Didelot if (err)
677ec561276SVivien Didelot return err;
678ec561276SVivien Didelot
679e289ef0dSVivien Didelot return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
680ec561276SVivien Didelot }
681ec561276SVivien Didelot
682e289ef0dSVivien Didelot /* 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)683e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_data_c22(struct mv88e6xxx_chip *chip,
684e289ef0dSVivien Didelot bool external, int dev, int reg,
685e289ef0dSVivien Didelot u16 data)
686e289ef0dSVivien Didelot {
687e289ef0dSVivien Didelot u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_WRITE_DATA;
688e289ef0dSVivien Didelot int err;
689e289ef0dSVivien Didelot
690e289ef0dSVivien Didelot err = mv88e6xxx_g2_smi_phy_wait(chip);
691e289ef0dSVivien Didelot if (err)
692e289ef0dSVivien Didelot return err;
693e289ef0dSVivien Didelot
694e289ef0dSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
695e289ef0dSVivien Didelot if (err)
696e289ef0dSVivien Didelot return err;
697e289ef0dSVivien Didelot
698e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
699e289ef0dSVivien Didelot }
700e289ef0dSVivien Didelot
mv88e6xxx_g2_smi_phy_access_c45(struct mv88e6xxx_chip * chip,bool external,u16 op,int port,int dev)701e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_access_c45(struct mv88e6xxx_chip *chip,
702e289ef0dSVivien Didelot bool external, u16 op, int port,
703e289ef0dSVivien Didelot int dev)
704e289ef0dSVivien Didelot {
705e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_access(chip, external, true, op, port, dev);
706e289ef0dSVivien Didelot }
707e289ef0dSVivien Didelot
708e289ef0dSVivien Didelot /* 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)709e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_addr_c45(struct mv88e6xxx_chip *chip,
710e289ef0dSVivien Didelot bool external, int port, int dev,
711e289ef0dSVivien Didelot int addr)
712e289ef0dSVivien Didelot {
713e289ef0dSVivien Didelot u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_ADDR;
714e289ef0dSVivien Didelot int err;
715e289ef0dSVivien Didelot
716e289ef0dSVivien Didelot err = mv88e6xxx_g2_smi_phy_wait(chip);
717e289ef0dSVivien Didelot if (err)
718e289ef0dSVivien Didelot return err;
719e289ef0dSVivien Didelot
720e289ef0dSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, addr);
721e289ef0dSVivien Didelot if (err)
722e289ef0dSVivien Didelot return err;
723e289ef0dSVivien Didelot
724e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
725e289ef0dSVivien Didelot }
726e289ef0dSVivien Didelot
727e289ef0dSVivien Didelot /* 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)728e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_read_data_c45(struct mv88e6xxx_chip *chip,
729e289ef0dSVivien Didelot bool external, int port, int dev,
730e289ef0dSVivien Didelot u16 *data)
731e289ef0dSVivien Didelot {
732e289ef0dSVivien Didelot u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_READ_DATA;
733e289ef0dSVivien Didelot int err;
734e289ef0dSVivien Didelot
735e289ef0dSVivien Didelot err = mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
736e289ef0dSVivien Didelot if (err)
737e289ef0dSVivien Didelot return err;
738e289ef0dSVivien Didelot
739e289ef0dSVivien Didelot return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
740e289ef0dSVivien Didelot }
741e289ef0dSVivien Didelot
_mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip * chip,bool external,int port,int devad,int reg,u16 * data)742743a19e3SAndrew Lunn static int _mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip,
743743a19e3SAndrew Lunn bool external, int port, int devad,
744743a19e3SAndrew Lunn int reg, u16 *data)
745e289ef0dSVivien Didelot {
746e289ef0dSVivien Didelot int err;
747e289ef0dSVivien Didelot
748743a19e3SAndrew Lunn err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, devad,
749743a19e3SAndrew Lunn reg);
750e289ef0dSVivien Didelot if (err)
751e289ef0dSVivien Didelot return err;
752e289ef0dSVivien Didelot
753743a19e3SAndrew Lunn return mv88e6xxx_g2_smi_phy_read_data_c45(chip, external, port, devad,
754e289ef0dSVivien Didelot data);
755e289ef0dSVivien Didelot }
756e289ef0dSVivien Didelot
757e289ef0dSVivien Didelot /* 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)758e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_data_c45(struct mv88e6xxx_chip *chip,
759e289ef0dSVivien Didelot bool external, int port, int dev,
760e289ef0dSVivien Didelot u16 data)
761e289ef0dSVivien Didelot {
762e289ef0dSVivien Didelot u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_DATA;
763e289ef0dSVivien Didelot int err;
764e289ef0dSVivien Didelot
765e289ef0dSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
766e289ef0dSVivien Didelot if (err)
767e289ef0dSVivien Didelot return err;
768e289ef0dSVivien Didelot
769e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev);
770e289ef0dSVivien Didelot }
771e289ef0dSVivien Didelot
_mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip * chip,bool external,int port,int devad,int reg,u16 data)772743a19e3SAndrew Lunn static int _mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip,
773743a19e3SAndrew Lunn bool external, int port, int devad,
774743a19e3SAndrew Lunn int reg, u16 data)
775e289ef0dSVivien Didelot {
776e289ef0dSVivien Didelot int err;
777e289ef0dSVivien Didelot
778743a19e3SAndrew Lunn err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, devad,
779743a19e3SAndrew Lunn reg);
780e289ef0dSVivien Didelot if (err)
781e289ef0dSVivien Didelot return err;
782e289ef0dSVivien Didelot
783743a19e3SAndrew Lunn return mv88e6xxx_g2_smi_phy_write_data_c45(chip, external, port, devad,
784e289ef0dSVivien Didelot data);
785e289ef0dSVivien Didelot }
786e289ef0dSVivien Didelot
mv88e6xxx_g2_smi_phy_read_c22(struct mv88e6xxx_chip * chip,struct mii_bus * bus,int addr,int reg,u16 * val)787743a19e3SAndrew Lunn int mv88e6xxx_g2_smi_phy_read_c22(struct mv88e6xxx_chip *chip,
788743a19e3SAndrew Lunn struct mii_bus *bus,
789cf3e80dfSAndrew Lunn int addr, int reg, u16 *val)
790cf3e80dfSAndrew Lunn {
791cf3e80dfSAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
792cf3e80dfSAndrew Lunn bool external = mdio_bus->external;
793cf3e80dfSAndrew Lunn
794e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_read_data_c22(chip, external, addr, reg,
795e289ef0dSVivien Didelot val);
796cf3e80dfSAndrew Lunn }
797cf3e80dfSAndrew Lunn
mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip * chip,struct mii_bus * bus,int addr,int devad,int reg,u16 * val)798743a19e3SAndrew Lunn int mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip,
799743a19e3SAndrew Lunn struct mii_bus *bus, int addr, int devad,
800743a19e3SAndrew Lunn int reg, u16 *val)
801cf3e80dfSAndrew Lunn {
802cf3e80dfSAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
803cf3e80dfSAndrew Lunn bool external = mdio_bus->external;
804cf3e80dfSAndrew Lunn
805743a19e3SAndrew Lunn return _mv88e6xxx_g2_smi_phy_read_c45(chip, external, addr, devad, reg,
806e289ef0dSVivien Didelot val);
807743a19e3SAndrew Lunn }
808743a19e3SAndrew Lunn
mv88e6xxx_g2_smi_phy_write_c22(struct mv88e6xxx_chip * chip,struct mii_bus * bus,int addr,int reg,u16 val)809743a19e3SAndrew Lunn int mv88e6xxx_g2_smi_phy_write_c22(struct mv88e6xxx_chip *chip,
810743a19e3SAndrew Lunn struct mii_bus *bus, int addr, int reg,
811743a19e3SAndrew Lunn u16 val)
812743a19e3SAndrew Lunn {
813743a19e3SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
814743a19e3SAndrew Lunn bool external = mdio_bus->external;
815cf3e80dfSAndrew Lunn
816e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_write_data_c22(chip, external, addr, reg,
817e289ef0dSVivien Didelot val);
818cf3e80dfSAndrew Lunn }
819cf3e80dfSAndrew Lunn
mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip * chip,struct mii_bus * bus,int addr,int devad,int reg,u16 val)820743a19e3SAndrew Lunn int mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip,
821743a19e3SAndrew Lunn struct mii_bus *bus, int addr, int devad,
822743a19e3SAndrew Lunn int reg, u16 val)
823743a19e3SAndrew Lunn {
824743a19e3SAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv;
825743a19e3SAndrew Lunn bool external = mdio_bus->external;
826743a19e3SAndrew Lunn
827743a19e3SAndrew Lunn return _mv88e6xxx_g2_smi_phy_write_c45(chip, external, addr, devad, reg,
828743a19e3SAndrew Lunn val);
829743a19e3SAndrew Lunn }
830743a19e3SAndrew Lunn
831a73ccd61SBrandon Streiff /* Offset 0x1B: Watchdog Control */
mv88e6097_watchdog_action(struct mv88e6xxx_chip * chip,int irq)832fcd25166SAndrew Lunn static int mv88e6097_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
833fcd25166SAndrew Lunn {
834fcd25166SAndrew Lunn u16 reg;
835fcd25166SAndrew Lunn
8363b19df73SVivien Didelot mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, ®);
837fcd25166SAndrew Lunn
838fcd25166SAndrew Lunn dev_info(chip->dev, "Watchdog event: 0x%04x", reg);
839fcd25166SAndrew Lunn
840fcd25166SAndrew Lunn return IRQ_HANDLED;
841fcd25166SAndrew Lunn }
842fcd25166SAndrew Lunn
mv88e6097_watchdog_free(struct mv88e6xxx_chip * chip)843fcd25166SAndrew Lunn static void mv88e6097_watchdog_free(struct mv88e6xxx_chip *chip)
844fcd25166SAndrew Lunn {
845fcd25166SAndrew Lunn u16 reg;
846fcd25166SAndrew Lunn
8473b19df73SVivien Didelot mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, ®);
848fcd25166SAndrew Lunn
8493b19df73SVivien Didelot reg &= ~(MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
8503b19df73SVivien Didelot MV88E6352_G2_WDOG_CTL_QC_ENABLE);
851fcd25166SAndrew Lunn
8523b19df73SVivien Didelot mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL, reg);
853fcd25166SAndrew Lunn }
854fcd25166SAndrew Lunn
mv88e6097_watchdog_setup(struct mv88e6xxx_chip * chip)855fcd25166SAndrew Lunn static int mv88e6097_watchdog_setup(struct mv88e6xxx_chip *chip)
856fcd25166SAndrew Lunn {
8573b19df73SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL,
8583b19df73SVivien Didelot MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
8593b19df73SVivien Didelot MV88E6352_G2_WDOG_CTL_QC_ENABLE |
8603b19df73SVivien Didelot MV88E6352_G2_WDOG_CTL_SWRESET);
861fcd25166SAndrew Lunn }
862fcd25166SAndrew Lunn
863fcd25166SAndrew Lunn const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {
864fcd25166SAndrew Lunn .irq_action = mv88e6097_watchdog_action,
865fcd25166SAndrew Lunn .irq_setup = mv88e6097_watchdog_setup,
866fcd25166SAndrew Lunn .irq_free = mv88e6097_watchdog_free,
867fcd25166SAndrew Lunn };
868fcd25166SAndrew Lunn
mv88e6250_watchdog_free(struct mv88e6xxx_chip * chip)869855cdfdeSRasmus Villemoes static void mv88e6250_watchdog_free(struct mv88e6xxx_chip *chip)
870855cdfdeSRasmus Villemoes {
871855cdfdeSRasmus Villemoes u16 reg;
872855cdfdeSRasmus Villemoes
873855cdfdeSRasmus Villemoes mv88e6xxx_g2_read(chip, MV88E6250_G2_WDOG_CTL, ®);
874855cdfdeSRasmus Villemoes
875855cdfdeSRasmus Villemoes reg &= ~(MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE |
876855cdfdeSRasmus Villemoes MV88E6250_G2_WDOG_CTL_QC_ENABLE);
877855cdfdeSRasmus Villemoes
878855cdfdeSRasmus Villemoes mv88e6xxx_g2_write(chip, MV88E6250_G2_WDOG_CTL, reg);
879855cdfdeSRasmus Villemoes }
880855cdfdeSRasmus Villemoes
mv88e6250_watchdog_setup(struct mv88e6xxx_chip * chip)881855cdfdeSRasmus Villemoes static int mv88e6250_watchdog_setup(struct mv88e6xxx_chip *chip)
882855cdfdeSRasmus Villemoes {
883855cdfdeSRasmus Villemoes return mv88e6xxx_g2_write(chip, MV88E6250_G2_WDOG_CTL,
884855cdfdeSRasmus Villemoes MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE |
885855cdfdeSRasmus Villemoes MV88E6250_G2_WDOG_CTL_QC_ENABLE |
886855cdfdeSRasmus Villemoes MV88E6250_G2_WDOG_CTL_SWRESET);
887855cdfdeSRasmus Villemoes }
888855cdfdeSRasmus Villemoes
889855cdfdeSRasmus Villemoes const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops = {
890855cdfdeSRasmus Villemoes .irq_action = mv88e6097_watchdog_action,
891855cdfdeSRasmus Villemoes .irq_setup = mv88e6250_watchdog_setup,
892855cdfdeSRasmus Villemoes .irq_free = mv88e6250_watchdog_free,
893855cdfdeSRasmus Villemoes };
894855cdfdeSRasmus Villemoes
mv88e6390_watchdog_setup(struct mv88e6xxx_chip * chip)89561303736SAndrew Lunn static int mv88e6390_watchdog_setup(struct mv88e6xxx_chip *chip)
89661303736SAndrew Lunn {
8972ad4da77SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
8982ad4da77SVivien Didelot MV88E6390_G2_WDOG_CTL_UPDATE |
8993b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE |
9003b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_CUT_THROUGH |
9013b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_QUEUE_CONTROLLER |
9023b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_EGRESS |
9033b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_FORCE_IRQ);
90461303736SAndrew Lunn }
90561303736SAndrew Lunn
mv88e6390_watchdog_action(struct mv88e6xxx_chip * chip,int irq)90661303736SAndrew Lunn static int mv88e6390_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
90761303736SAndrew Lunn {
90861303736SAndrew Lunn u16 reg;
90961303736SAndrew Lunn
9103b19df73SVivien Didelot mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
9113b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_PTR_EVENT);
912b672b351SAndrew Lunn mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, ®);
91361303736SAndrew Lunn
91461303736SAndrew Lunn dev_info(chip->dev, "Watchdog event: 0x%04x",
9153b19df73SVivien Didelot reg & MV88E6390_G2_WDOG_CTL_DATA_MASK);
91661303736SAndrew Lunn
9173b19df73SVivien Didelot mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
9183b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_PTR_HISTORY);
919b672b351SAndrew Lunn mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, ®);
92061303736SAndrew Lunn
92161303736SAndrew Lunn dev_info(chip->dev, "Watchdog history: 0x%04x",
9223b19df73SVivien Didelot reg & MV88E6390_G2_WDOG_CTL_DATA_MASK);
92361303736SAndrew Lunn
92461303736SAndrew Lunn /* Trigger a software reset to try to recover the switch */
92561303736SAndrew Lunn if (chip->info->ops->reset)
92661303736SAndrew Lunn chip->info->ops->reset(chip);
92761303736SAndrew Lunn
92861303736SAndrew Lunn mv88e6390_watchdog_setup(chip);
92961303736SAndrew Lunn
93061303736SAndrew Lunn return IRQ_HANDLED;
93161303736SAndrew Lunn }
93261303736SAndrew Lunn
mv88e6390_watchdog_free(struct mv88e6xxx_chip * chip)93361303736SAndrew Lunn static void mv88e6390_watchdog_free(struct mv88e6xxx_chip *chip)
93461303736SAndrew Lunn {
9352ad4da77SVivien Didelot mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
9362ad4da77SVivien Didelot MV88E6390_G2_WDOG_CTL_UPDATE |
9373b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE);
93861303736SAndrew Lunn }
93961303736SAndrew Lunn
94061303736SAndrew Lunn const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {
94161303736SAndrew Lunn .irq_action = mv88e6390_watchdog_action,
94261303736SAndrew Lunn .irq_setup = mv88e6390_watchdog_setup,
94361303736SAndrew Lunn .irq_free = mv88e6390_watchdog_free,
94461303736SAndrew Lunn };
94561303736SAndrew Lunn
mv88e6393x_watchdog_action(struct mv88e6xxx_chip * chip,int irq)946089b91a0SGustav Ekelund static int mv88e6393x_watchdog_action(struct mv88e6xxx_chip *chip, int irq)
947089b91a0SGustav Ekelund {
948089b91a0SGustav Ekelund mv88e6390_watchdog_action(chip, irq);
949089b91a0SGustav Ekelund
950089b91a0SGustav Ekelund /* Fix for clearing the force WD event bit.
951089b91a0SGustav Ekelund * Unreleased erratum on mv88e6393x.
952089b91a0SGustav Ekelund */
953089b91a0SGustav Ekelund mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL,
954089b91a0SGustav Ekelund MV88E6390_G2_WDOG_CTL_UPDATE |
955089b91a0SGustav Ekelund MV88E6390_G2_WDOG_CTL_PTR_EVENT);
956089b91a0SGustav Ekelund
957089b91a0SGustav Ekelund return IRQ_HANDLED;
958089b91a0SGustav Ekelund }
959089b91a0SGustav Ekelund
960089b91a0SGustav Ekelund const struct mv88e6xxx_irq_ops mv88e6393x_watchdog_ops = {
961089b91a0SGustav Ekelund .irq_action = mv88e6393x_watchdog_action,
962089b91a0SGustav Ekelund .irq_setup = mv88e6390_watchdog_setup,
963089b91a0SGustav Ekelund .irq_free = mv88e6390_watchdog_free,
964089b91a0SGustav Ekelund };
965089b91a0SGustav Ekelund
mv88e6xxx_g2_watchdog_thread_fn(int irq,void * dev_id)966fcd25166SAndrew Lunn static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id)
967fcd25166SAndrew Lunn {
968fcd25166SAndrew Lunn struct mv88e6xxx_chip *chip = dev_id;
969fcd25166SAndrew Lunn irqreturn_t ret = IRQ_NONE;
970fcd25166SAndrew Lunn
971c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip);
972fcd25166SAndrew Lunn if (chip->info->ops->watchdog_ops->irq_action)
973fcd25166SAndrew Lunn ret = chip->info->ops->watchdog_ops->irq_action(chip, irq);
974c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip);
975fcd25166SAndrew Lunn
976fcd25166SAndrew Lunn return ret;
977fcd25166SAndrew Lunn }
978fcd25166SAndrew Lunn
mv88e6xxx_g2_watchdog_free(struct mv88e6xxx_chip * chip)979fcd25166SAndrew Lunn static void mv88e6xxx_g2_watchdog_free(struct mv88e6xxx_chip *chip)
980fcd25166SAndrew Lunn {
981c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip);
982fcd25166SAndrew Lunn if (chip->info->ops->watchdog_ops->irq_free)
983fcd25166SAndrew Lunn chip->info->ops->watchdog_ops->irq_free(chip);
984c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip);
985fcd25166SAndrew Lunn
986fcd25166SAndrew Lunn free_irq(chip->watchdog_irq, chip);
987fcd25166SAndrew Lunn irq_dispose_mapping(chip->watchdog_irq);
988fcd25166SAndrew Lunn }
989fcd25166SAndrew Lunn
mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip * chip)990fcd25166SAndrew Lunn static int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip)
991fcd25166SAndrew Lunn {
992fcd25166SAndrew Lunn int err;
993fcd25166SAndrew Lunn
994fcd25166SAndrew Lunn chip->watchdog_irq = irq_find_mapping(chip->g2_irq.domain,
9951d90016dSVivien Didelot MV88E6XXX_G2_INT_SOURCE_WATCHDOG);
996fcd25166SAndrew Lunn if (chip->watchdog_irq < 0)
997fcd25166SAndrew Lunn return chip->watchdog_irq;
998fcd25166SAndrew Lunn
9998b4db289SAndrew Lunn snprintf(chip->watchdog_irq_name, sizeof(chip->watchdog_irq_name),
10008b4db289SAndrew Lunn "mv88e6xxx-%s-watchdog", dev_name(chip->dev));
10018b4db289SAndrew Lunn
1002fcd25166SAndrew Lunn err = request_threaded_irq(chip->watchdog_irq, NULL,
1003fcd25166SAndrew Lunn mv88e6xxx_g2_watchdog_thread_fn,
1004fcd25166SAndrew Lunn IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
10058b4db289SAndrew Lunn chip->watchdog_irq_name, chip);
1006fcd25166SAndrew Lunn if (err)
1007fcd25166SAndrew Lunn return err;
1008fcd25166SAndrew Lunn
1009c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip);
1010fcd25166SAndrew Lunn if (chip->info->ops->watchdog_ops->irq_setup)
1011fcd25166SAndrew Lunn err = chip->info->ops->watchdog_ops->irq_setup(chip);
1012c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip);
1013fcd25166SAndrew Lunn
1014fcd25166SAndrew Lunn return err;
1015fcd25166SAndrew Lunn }
1016fcd25166SAndrew Lunn
101781228996SVivien Didelot /* Offset 0x1D: Misc Register */
101881228996SVivien Didelot
mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip * chip,bool port_5_bit)101981228996SVivien Didelot static int mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip *chip,
102081228996SVivien Didelot bool port_5_bit)
102181228996SVivien Didelot {
102281228996SVivien Didelot u16 val;
102381228996SVivien Didelot int err;
102481228996SVivien Didelot
10251d90016dSVivien Didelot err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_MISC, &val);
102681228996SVivien Didelot if (err)
102781228996SVivien Didelot return err;
102881228996SVivien Didelot
102981228996SVivien Didelot if (port_5_bit)
10301d90016dSVivien Didelot val |= MV88E6XXX_G2_MISC_5_BIT_PORT;
103181228996SVivien Didelot else
10321d90016dSVivien Didelot val &= ~MV88E6XXX_G2_MISC_5_BIT_PORT;
103381228996SVivien Didelot
10341d90016dSVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MISC, val);
103581228996SVivien Didelot }
103681228996SVivien Didelot
mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip * chip)103781228996SVivien Didelot int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip)
103881228996SVivien Didelot {
103981228996SVivien Didelot return mv88e6xxx_g2_misc_5_bit_port(chip, false);
104081228996SVivien Didelot }
104181228996SVivien Didelot
mv88e6xxx_g2_irq_mask(struct irq_data * d)1042dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_mask(struct irq_data *d)
1043dc30c35bSAndrew Lunn {
1044dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
1045dc30c35bSAndrew Lunn unsigned int n = d->hwirq;
1046dc30c35bSAndrew Lunn
1047dc30c35bSAndrew Lunn chip->g2_irq.masked |= (1 << n);
1048dc30c35bSAndrew Lunn }
1049dc30c35bSAndrew Lunn
mv88e6xxx_g2_irq_unmask(struct irq_data * d)1050dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_unmask(struct irq_data *d)
1051dc30c35bSAndrew Lunn {
1052dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
1053dc30c35bSAndrew Lunn unsigned int n = d->hwirq;
1054dc30c35bSAndrew Lunn
1055dc30c35bSAndrew Lunn chip->g2_irq.masked &= ~(1 << n);
1056dc30c35bSAndrew Lunn }
1057dc30c35bSAndrew Lunn
mv88e6xxx_g2_irq_thread_fn(int irq,void * dev_id)1058dc30c35bSAndrew Lunn static irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id)
1059dc30c35bSAndrew Lunn {
1060dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = dev_id;
1061dc30c35bSAndrew Lunn unsigned int nhandled = 0;
1062dc30c35bSAndrew Lunn unsigned int sub_irq;
1063dc30c35bSAndrew Lunn unsigned int n;
1064dc30c35bSAndrew Lunn int err;
1065dc30c35bSAndrew Lunn u16 reg;
1066dc30c35bSAndrew Lunn
1067c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip);
1068d6c5e6afSVivien Didelot err = mv88e6xxx_g2_int_source(chip, ®);
1069c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip);
1070dc30c35bSAndrew Lunn if (err)
1071dc30c35bSAndrew Lunn goto out;
1072dc30c35bSAndrew Lunn
1073dc30c35bSAndrew Lunn for (n = 0; n < 16; ++n) {
1074dc30c35bSAndrew Lunn if (reg & (1 << n)) {
1075dc30c35bSAndrew Lunn sub_irq = irq_find_mapping(chip->g2_irq.domain, n);
1076dc30c35bSAndrew Lunn handle_nested_irq(sub_irq);
1077dc30c35bSAndrew Lunn ++nhandled;
1078dc30c35bSAndrew Lunn }
1079dc30c35bSAndrew Lunn }
1080dc30c35bSAndrew Lunn out:
1081dc30c35bSAndrew Lunn return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
1082dc30c35bSAndrew Lunn }
1083dc30c35bSAndrew Lunn
mv88e6xxx_g2_irq_bus_lock(struct irq_data * d)1084dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_bus_lock(struct irq_data *d)
1085dc30c35bSAndrew Lunn {
1086dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
1087dc30c35bSAndrew Lunn
1088c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip);
1089dc30c35bSAndrew Lunn }
1090dc30c35bSAndrew Lunn
mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data * d)1091dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d)
1092dc30c35bSAndrew Lunn {
1093dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
1094d6c5e6afSVivien Didelot int err;
1095dc30c35bSAndrew Lunn
1096d6c5e6afSVivien Didelot err = mv88e6xxx_g2_int_mask(chip, ~chip->g2_irq.masked);
1097d6c5e6afSVivien Didelot if (err)
1098d6c5e6afSVivien Didelot dev_err(chip->dev, "failed to mask interrupts\n");
1099dc30c35bSAndrew Lunn
1100c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip);
1101dc30c35bSAndrew Lunn }
1102dc30c35bSAndrew Lunn
11036eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g2_irq_chip = {
1104dc30c35bSAndrew Lunn .name = "mv88e6xxx-g2",
1105dc30c35bSAndrew Lunn .irq_mask = mv88e6xxx_g2_irq_mask,
1106dc30c35bSAndrew Lunn .irq_unmask = mv88e6xxx_g2_irq_unmask,
1107dc30c35bSAndrew Lunn .irq_bus_lock = mv88e6xxx_g2_irq_bus_lock,
1108dc30c35bSAndrew Lunn .irq_bus_sync_unlock = mv88e6xxx_g2_irq_bus_sync_unlock,
1109dc30c35bSAndrew Lunn };
1110dc30c35bSAndrew Lunn
mv88e6xxx_g2_irq_domain_map(struct irq_domain * d,unsigned int irq,irq_hw_number_t hwirq)1111dc30c35bSAndrew Lunn static int mv88e6xxx_g2_irq_domain_map(struct irq_domain *d,
1112dc30c35bSAndrew Lunn unsigned int irq,
1113dc30c35bSAndrew Lunn irq_hw_number_t hwirq)
1114dc30c35bSAndrew Lunn {
1115dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = d->host_data;
1116dc30c35bSAndrew Lunn
1117dc30c35bSAndrew Lunn irq_set_chip_data(irq, d->host_data);
1118dc30c35bSAndrew Lunn irq_set_chip_and_handler(irq, &chip->g2_irq.chip, handle_level_irq);
1119dc30c35bSAndrew Lunn irq_set_noprobe(irq);
1120dc30c35bSAndrew Lunn
1121dc30c35bSAndrew Lunn return 0;
1122dc30c35bSAndrew Lunn }
1123dc30c35bSAndrew Lunn
1124dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g2_irq_domain_ops = {
1125dc30c35bSAndrew Lunn .map = mv88e6xxx_g2_irq_domain_map,
1126dc30c35bSAndrew Lunn .xlate = irq_domain_xlate_twocell,
1127dc30c35bSAndrew Lunn };
1128dc30c35bSAndrew Lunn
mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip * chip)1129dc30c35bSAndrew Lunn void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip)
1130dc30c35bSAndrew Lunn {
1131dc30c35bSAndrew Lunn int irq, virq;
1132dc30c35bSAndrew Lunn
1133fcd25166SAndrew Lunn mv88e6xxx_g2_watchdog_free(chip);
1134fcd25166SAndrew Lunn
11358e757ebaSAndrew Lunn free_irq(chip->device_irq, chip);
11368e757ebaSAndrew Lunn irq_dispose_mapping(chip->device_irq);
11378e757ebaSAndrew Lunn
1138dc30c35bSAndrew Lunn for (irq = 0; irq < 16; irq++) {
1139dc30c35bSAndrew Lunn virq = irq_find_mapping(chip->g2_irq.domain, irq);
1140dc30c35bSAndrew Lunn irq_dispose_mapping(virq);
1141dc30c35bSAndrew Lunn }
1142dc30c35bSAndrew Lunn
1143dc30c35bSAndrew Lunn irq_domain_remove(chip->g2_irq.domain);
1144dc30c35bSAndrew Lunn }
1145dc30c35bSAndrew Lunn
mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip * chip)1146dc30c35bSAndrew Lunn int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip)
1147dc30c35bSAndrew Lunn {
11488e757ebaSAndrew Lunn int err, irq, virq;
1149dc30c35bSAndrew Lunn
11500395823bSRussell King chip->g2_irq.masked = ~0;
11510395823bSRussell King mv88e6xxx_reg_lock(chip);
11520395823bSRussell King err = mv88e6xxx_g2_int_mask(chip, ~chip->g2_irq.masked);
11530395823bSRussell King mv88e6xxx_reg_unlock(chip);
11540395823bSRussell King if (err)
11550395823bSRussell King return err;
11560395823bSRussell King
1157dc30c35bSAndrew Lunn chip->g2_irq.domain = irq_domain_add_simple(
1158dc30c35bSAndrew Lunn chip->dev->of_node, 16, 0, &mv88e6xxx_g2_irq_domain_ops, chip);
1159dc30c35bSAndrew Lunn if (!chip->g2_irq.domain)
1160dc30c35bSAndrew Lunn return -ENOMEM;
1161dc30c35bSAndrew Lunn
1162dc30c35bSAndrew Lunn for (irq = 0; irq < 16; irq++)
1163dc30c35bSAndrew Lunn irq_create_mapping(chip->g2_irq.domain, irq);
1164dc30c35bSAndrew Lunn
1165dc30c35bSAndrew Lunn chip->g2_irq.chip = mv88e6xxx_g2_irq_chip;
1166dc30c35bSAndrew Lunn
11678e757ebaSAndrew Lunn chip->device_irq = irq_find_mapping(chip->g1_irq.domain,
116882466921SVivien Didelot MV88E6XXX_G1_STS_IRQ_DEVICE);
11698e757ebaSAndrew Lunn if (chip->device_irq < 0) {
11708e757ebaSAndrew Lunn err = chip->device_irq;
1171dc30c35bSAndrew Lunn goto out;
1172dc30c35bSAndrew Lunn }
1173dc30c35bSAndrew Lunn
117406acd114SAndrew Lunn snprintf(chip->device_irq_name, sizeof(chip->device_irq_name),
117506acd114SAndrew Lunn "mv88e6xxx-%s-g2", dev_name(chip->dev));
117606acd114SAndrew Lunn
11778e757ebaSAndrew Lunn err = request_threaded_irq(chip->device_irq, NULL,
1178dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_thread_fn,
117906acd114SAndrew Lunn IRQF_ONESHOT, chip->device_irq_name, chip);
1180dc30c35bSAndrew Lunn if (err)
1181dc30c35bSAndrew Lunn goto out;
1182dc30c35bSAndrew Lunn
1183fcd25166SAndrew Lunn return mv88e6xxx_g2_watchdog_setup(chip);
11848e757ebaSAndrew Lunn
1185dc30c35bSAndrew Lunn out:
11868e757ebaSAndrew Lunn for (irq = 0; irq < 16; irq++) {
11878e757ebaSAndrew Lunn virq = irq_find_mapping(chip->g2_irq.domain, irq);
11888e757ebaSAndrew Lunn irq_dispose_mapping(virq);
11898e757ebaSAndrew Lunn }
11908e757ebaSAndrew Lunn
11918e757ebaSAndrew Lunn irq_domain_remove(chip->g2_irq.domain);
1192dc30c35bSAndrew Lunn
1193dc30c35bSAndrew Lunn return err;
1194dc30c35bSAndrew Lunn }
1195dc30c35bSAndrew Lunn
mv88e6xxx_g2_irq_mdio_setup(struct mv88e6xxx_chip * chip,struct mii_bus * bus)11966f88284fSAndrew Lunn int mv88e6xxx_g2_irq_mdio_setup(struct mv88e6xxx_chip *chip,
11976f88284fSAndrew Lunn struct mii_bus *bus)
11986f88284fSAndrew Lunn {
11993ba89b28SAlexis Lothoré int phy_start = chip->info->internal_phys_offset;
12003ba89b28SAlexis Lothoré int phy_end = chip->info->internal_phys_offset +
12013ba89b28SAlexis Lothoré chip->info->num_internal_phys;
1202b1a2de9cSVladimir Oltean int phy, irq;
12036f88284fSAndrew Lunn
12043ba89b28SAlexis Lothoré for (phy = phy_start; phy < phy_end; phy++) {
12056f88284fSAndrew Lunn irq = irq_find_mapping(chip->g2_irq.domain, phy);
1206b1a2de9cSVladimir Oltean if (irq < 0)
1207b1a2de9cSVladimir Oltean return irq;
1208b1a2de9cSVladimir Oltean
12099255bacdSAndrew Lunn bus->irq[chip->info->phy_base_addr + phy] = irq;
12106f88284fSAndrew Lunn }
12116f88284fSAndrew Lunn return 0;
12126f88284fSAndrew Lunn }
12136f88284fSAndrew Lunn
mv88e6xxx_g2_irq_mdio_free(struct mv88e6xxx_chip * chip,struct mii_bus * bus)12146f88284fSAndrew Lunn void mv88e6xxx_g2_irq_mdio_free(struct mv88e6xxx_chip *chip,
12156f88284fSAndrew Lunn struct mii_bus *bus)
12166f88284fSAndrew Lunn {
12176f88284fSAndrew Lunn }
1218