12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2ec561276SVivien Didelot /* 31d90016dSVivien Didelot * Marvell 88E6xxx Switch Global 2 Registers support 4ec561276SVivien Didelot * 5ec561276SVivien Didelot * Copyright (c) 2008 Marvell Semiconductor 6ec561276SVivien Didelot * 74333d619SVivien Didelot * Copyright (c) 2016-2017 Savoir-faire Linux Inc. 84333d619SVivien Didelot * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 9ec561276SVivien Didelot */ 10ec561276SVivien Didelot 11e289ef0dSVivien Didelot #include <linux/bitfield.h> 12282ccf6eSFlorian Westphal #include <linux/interrupt.h> 13dc30c35bSAndrew Lunn #include <linux/irqdomain.h> 144d5f2ba7SVivien Didelot 154d5f2ba7SVivien Didelot #include "chip.h" 1682466921SVivien Didelot #include "global1.h" /* for MV88E6XXX_G1_STS_IRQ_DEVICE */ 17ec561276SVivien Didelot #include "global2.h" 18ec561276SVivien Didelot 19b000be95SBrandon Streiff int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) 209fe850fbSVivien Didelot { 219069c13aSVivien Didelot return mv88e6xxx_read(chip, chip->info->global2_addr, reg, val); 229fe850fbSVivien Didelot } 239fe850fbSVivien Didelot 24b000be95SBrandon Streiff int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val) 259fe850fbSVivien Didelot { 269069c13aSVivien Didelot return mv88e6xxx_write(chip, chip->info->global2_addr, reg, val); 279fe850fbSVivien Didelot } 289fe850fbSVivien Didelot 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 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 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 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 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 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 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 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 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 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 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 153b28f872dSVivien Didelot int mv88e6xxx_g2_trunk_clear(struct mv88e6xxx_chip *chip) 154ec561276SVivien Didelot { 155370b4ffbSVivien Didelot const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1; 156ec561276SVivien Didelot int i, err; 157ec561276SVivien Didelot 158ec561276SVivien Didelot /* Clear all eight possible Trunk Mask vectors */ 159ec561276SVivien Didelot for (i = 0; i < 8; ++i) { 160ec561276SVivien Didelot err = mv88e6xxx_g2_trunk_mask_write(chip, i, false, port_mask); 161ec561276SVivien Didelot if (err) 162ec561276SVivien Didelot return err; 163ec561276SVivien Didelot } 164ec561276SVivien Didelot 165ec561276SVivien Didelot /* Clear all sixteen possible Trunk ID routing vectors */ 166ec561276SVivien Didelot for (i = 0; i < 16; ++i) { 167ec561276SVivien Didelot err = mv88e6xxx_g2_trunk_mapping_write(chip, i, 0); 168ec561276SVivien Didelot if (err) 169ec561276SVivien Didelot return err; 170ec561276SVivien Didelot } 171ec561276SVivien Didelot 172ec561276SVivien Didelot return 0; 173ec561276SVivien Didelot } 174ec561276SVivien Didelot 175ec561276SVivien Didelot /* Offset 0x09: Ingress Rate Command register 176ec561276SVivien Didelot * Offset 0x0A: Ingress Rate Data register 177ec561276SVivien Didelot */ 178ec561276SVivien Didelot 179cd8da8bbSVivien Didelot static int mv88e6xxx_g2_irl_wait(struct mv88e6xxx_chip *chip) 180ec561276SVivien Didelot { 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 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 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 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 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 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 242*836021a2STobias Waldekranz int mv88e6xxx_g2_pvt_read(struct mv88e6xxx_chip *chip, int src_dev, 243*836021a2STobias Waldekranz int src_port, u16 *data) 244*836021a2STobias Waldekranz { 245*836021a2STobias Waldekranz int err; 246*836021a2STobias Waldekranz 247*836021a2STobias Waldekranz err = mv88e6xxx_g2_pvt_op_wait(chip); 248*836021a2STobias Waldekranz if (err) 249*836021a2STobias Waldekranz return err; 250*836021a2STobias Waldekranz 251*836021a2STobias Waldekranz err = mv88e6xxx_g2_pvt_op(chip, src_dev, src_port, 252*836021a2STobias Waldekranz MV88E6XXX_G2_PVT_ADDR_OP_READ); 253*836021a2STobias Waldekranz if (err) 254*836021a2STobias Waldekranz return err; 255*836021a2STobias Waldekranz 256*836021a2STobias Waldekranz return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_PVT_DATA, data); 257*836021a2STobias Waldekranz } 258*836021a2STobias Waldekranz 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 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 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 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 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 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 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 343ec561276SVivien Didelot static 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 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 */ 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 */ 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 742e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip, 743e289ef0dSVivien Didelot bool external, int port, int reg, 744e289ef0dSVivien Didelot u16 *data) 745e289ef0dSVivien Didelot { 746e289ef0dSVivien Didelot int dev = (reg >> 16) & 0x1f; 747e289ef0dSVivien Didelot int addr = reg & 0xffff; 748e289ef0dSVivien Didelot int err; 749e289ef0dSVivien Didelot 750e289ef0dSVivien Didelot err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev, 751e289ef0dSVivien Didelot addr); 752e289ef0dSVivien Didelot if (err) 753e289ef0dSVivien Didelot return err; 754e289ef0dSVivien Didelot 755e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_read_data_c45(chip, external, port, dev, 756e289ef0dSVivien Didelot data); 757e289ef0dSVivien Didelot } 758e289ef0dSVivien Didelot 759e289ef0dSVivien Didelot /* IEEE 802.3 Clause 45 Write Data Register */ 760e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_data_c45(struct mv88e6xxx_chip *chip, 761e289ef0dSVivien Didelot bool external, int port, int dev, 762e289ef0dSVivien Didelot u16 data) 763e289ef0dSVivien Didelot { 764e289ef0dSVivien Didelot u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_DATA; 765e289ef0dSVivien Didelot int err; 766e289ef0dSVivien Didelot 767e289ef0dSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data); 768e289ef0dSVivien Didelot if (err) 769e289ef0dSVivien Didelot return err; 770e289ef0dSVivien Didelot 771e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev); 772e289ef0dSVivien Didelot } 773e289ef0dSVivien Didelot 774e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip, 775e289ef0dSVivien Didelot bool external, int port, int reg, 776e289ef0dSVivien Didelot u16 data) 777e289ef0dSVivien Didelot { 778e289ef0dSVivien Didelot int dev = (reg >> 16) & 0x1f; 779e289ef0dSVivien Didelot int addr = reg & 0xffff; 780e289ef0dSVivien Didelot int err; 781e289ef0dSVivien Didelot 782e289ef0dSVivien Didelot err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev, 783e289ef0dSVivien Didelot addr); 784e289ef0dSVivien Didelot if (err) 785e289ef0dSVivien Didelot return err; 786e289ef0dSVivien Didelot 787e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_write_data_c45(chip, external, port, dev, 788e289ef0dSVivien Didelot data); 789e289ef0dSVivien Didelot } 790e289ef0dSVivien Didelot 791e289ef0dSVivien Didelot int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, 792cf3e80dfSAndrew Lunn int addr, int reg, u16 *val) 793cf3e80dfSAndrew Lunn { 794cf3e80dfSAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 795cf3e80dfSAndrew Lunn bool external = mdio_bus->external; 796cf3e80dfSAndrew Lunn 797cf3e80dfSAndrew Lunn if (reg & MII_ADDR_C45) 798e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_read_c45(chip, external, addr, reg, 799e289ef0dSVivien Didelot val); 800e289ef0dSVivien Didelot 801e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_read_data_c22(chip, external, addr, reg, 802e289ef0dSVivien Didelot val); 803cf3e80dfSAndrew Lunn } 804cf3e80dfSAndrew Lunn 805e289ef0dSVivien Didelot int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, 806cf3e80dfSAndrew Lunn int addr, int reg, u16 val) 807cf3e80dfSAndrew Lunn { 808cf3e80dfSAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 809cf3e80dfSAndrew Lunn bool external = mdio_bus->external; 810cf3e80dfSAndrew Lunn 811cf3e80dfSAndrew Lunn if (reg & MII_ADDR_C45) 812e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_write_c45(chip, external, addr, reg, 813e289ef0dSVivien Didelot val); 814cf3e80dfSAndrew Lunn 815e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_write_data_c22(chip, external, addr, reg, 816e289ef0dSVivien Didelot val); 817cf3e80dfSAndrew Lunn } 818cf3e80dfSAndrew Lunn 819a73ccd61SBrandon Streiff /* Offset 0x1B: Watchdog Control */ 820fcd25166SAndrew Lunn static int mv88e6097_watchdog_action(struct mv88e6xxx_chip *chip, int irq) 821fcd25166SAndrew Lunn { 822fcd25166SAndrew Lunn u16 reg; 823fcd25166SAndrew Lunn 8243b19df73SVivien Didelot mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, ®); 825fcd25166SAndrew Lunn 826fcd25166SAndrew Lunn dev_info(chip->dev, "Watchdog event: 0x%04x", reg); 827fcd25166SAndrew Lunn 828fcd25166SAndrew Lunn return IRQ_HANDLED; 829fcd25166SAndrew Lunn } 830fcd25166SAndrew Lunn 831fcd25166SAndrew Lunn static void mv88e6097_watchdog_free(struct mv88e6xxx_chip *chip) 832fcd25166SAndrew Lunn { 833fcd25166SAndrew Lunn u16 reg; 834fcd25166SAndrew Lunn 8353b19df73SVivien Didelot mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, ®); 836fcd25166SAndrew Lunn 8373b19df73SVivien Didelot reg &= ~(MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE | 8383b19df73SVivien Didelot MV88E6352_G2_WDOG_CTL_QC_ENABLE); 839fcd25166SAndrew Lunn 8403b19df73SVivien Didelot mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL, reg); 841fcd25166SAndrew Lunn } 842fcd25166SAndrew Lunn 843fcd25166SAndrew Lunn static int mv88e6097_watchdog_setup(struct mv88e6xxx_chip *chip) 844fcd25166SAndrew Lunn { 8453b19df73SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL, 8463b19df73SVivien Didelot MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE | 8473b19df73SVivien Didelot MV88E6352_G2_WDOG_CTL_QC_ENABLE | 8483b19df73SVivien Didelot MV88E6352_G2_WDOG_CTL_SWRESET); 849fcd25166SAndrew Lunn } 850fcd25166SAndrew Lunn 851fcd25166SAndrew Lunn const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = { 852fcd25166SAndrew Lunn .irq_action = mv88e6097_watchdog_action, 853fcd25166SAndrew Lunn .irq_setup = mv88e6097_watchdog_setup, 854fcd25166SAndrew Lunn .irq_free = mv88e6097_watchdog_free, 855fcd25166SAndrew Lunn }; 856fcd25166SAndrew Lunn 857855cdfdeSRasmus Villemoes static void mv88e6250_watchdog_free(struct mv88e6xxx_chip *chip) 858855cdfdeSRasmus Villemoes { 859855cdfdeSRasmus Villemoes u16 reg; 860855cdfdeSRasmus Villemoes 861855cdfdeSRasmus Villemoes mv88e6xxx_g2_read(chip, MV88E6250_G2_WDOG_CTL, ®); 862855cdfdeSRasmus Villemoes 863855cdfdeSRasmus Villemoes reg &= ~(MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE | 864855cdfdeSRasmus Villemoes MV88E6250_G2_WDOG_CTL_QC_ENABLE); 865855cdfdeSRasmus Villemoes 866855cdfdeSRasmus Villemoes mv88e6xxx_g2_write(chip, MV88E6250_G2_WDOG_CTL, reg); 867855cdfdeSRasmus Villemoes } 868855cdfdeSRasmus Villemoes 869855cdfdeSRasmus Villemoes static int mv88e6250_watchdog_setup(struct mv88e6xxx_chip *chip) 870855cdfdeSRasmus Villemoes { 871855cdfdeSRasmus Villemoes return mv88e6xxx_g2_write(chip, MV88E6250_G2_WDOG_CTL, 872855cdfdeSRasmus Villemoes MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE | 873855cdfdeSRasmus Villemoes MV88E6250_G2_WDOG_CTL_QC_ENABLE | 874855cdfdeSRasmus Villemoes MV88E6250_G2_WDOG_CTL_SWRESET); 875855cdfdeSRasmus Villemoes } 876855cdfdeSRasmus Villemoes 877855cdfdeSRasmus Villemoes const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops = { 878855cdfdeSRasmus Villemoes .irq_action = mv88e6097_watchdog_action, 879855cdfdeSRasmus Villemoes .irq_setup = mv88e6250_watchdog_setup, 880855cdfdeSRasmus Villemoes .irq_free = mv88e6250_watchdog_free, 881855cdfdeSRasmus Villemoes }; 882855cdfdeSRasmus Villemoes 88361303736SAndrew Lunn static int mv88e6390_watchdog_setup(struct mv88e6xxx_chip *chip) 88461303736SAndrew Lunn { 8852ad4da77SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL, 8862ad4da77SVivien Didelot MV88E6390_G2_WDOG_CTL_UPDATE | 8873b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE | 8883b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_CUT_THROUGH | 8893b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_QUEUE_CONTROLLER | 8903b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_EGRESS | 8913b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_FORCE_IRQ); 89261303736SAndrew Lunn } 89361303736SAndrew Lunn 89461303736SAndrew Lunn static int mv88e6390_watchdog_action(struct mv88e6xxx_chip *chip, int irq) 89561303736SAndrew Lunn { 89661303736SAndrew Lunn u16 reg; 89761303736SAndrew Lunn 8983b19df73SVivien Didelot mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL, 8993b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_PTR_EVENT); 900b672b351SAndrew Lunn mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, ®); 90161303736SAndrew Lunn 90261303736SAndrew Lunn dev_info(chip->dev, "Watchdog event: 0x%04x", 9033b19df73SVivien Didelot reg & MV88E6390_G2_WDOG_CTL_DATA_MASK); 90461303736SAndrew Lunn 9053b19df73SVivien Didelot mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL, 9063b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_PTR_HISTORY); 907b672b351SAndrew Lunn mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, ®); 90861303736SAndrew Lunn 90961303736SAndrew Lunn dev_info(chip->dev, "Watchdog history: 0x%04x", 9103b19df73SVivien Didelot reg & MV88E6390_G2_WDOG_CTL_DATA_MASK); 91161303736SAndrew Lunn 91261303736SAndrew Lunn /* Trigger a software reset to try to recover the switch */ 91361303736SAndrew Lunn if (chip->info->ops->reset) 91461303736SAndrew Lunn chip->info->ops->reset(chip); 91561303736SAndrew Lunn 91661303736SAndrew Lunn mv88e6390_watchdog_setup(chip); 91761303736SAndrew Lunn 91861303736SAndrew Lunn return IRQ_HANDLED; 91961303736SAndrew Lunn } 92061303736SAndrew Lunn 92161303736SAndrew Lunn static void mv88e6390_watchdog_free(struct mv88e6xxx_chip *chip) 92261303736SAndrew Lunn { 9232ad4da77SVivien Didelot mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL, 9242ad4da77SVivien Didelot MV88E6390_G2_WDOG_CTL_UPDATE | 9253b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE); 92661303736SAndrew Lunn } 92761303736SAndrew Lunn 92861303736SAndrew Lunn const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = { 92961303736SAndrew Lunn .irq_action = mv88e6390_watchdog_action, 93061303736SAndrew Lunn .irq_setup = mv88e6390_watchdog_setup, 93161303736SAndrew Lunn .irq_free = mv88e6390_watchdog_free, 93261303736SAndrew Lunn }; 93361303736SAndrew Lunn 934fcd25166SAndrew Lunn static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id) 935fcd25166SAndrew Lunn { 936fcd25166SAndrew Lunn struct mv88e6xxx_chip *chip = dev_id; 937fcd25166SAndrew Lunn irqreturn_t ret = IRQ_NONE; 938fcd25166SAndrew Lunn 939c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 940fcd25166SAndrew Lunn if (chip->info->ops->watchdog_ops->irq_action) 941fcd25166SAndrew Lunn ret = chip->info->ops->watchdog_ops->irq_action(chip, irq); 942c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 943fcd25166SAndrew Lunn 944fcd25166SAndrew Lunn return ret; 945fcd25166SAndrew Lunn } 946fcd25166SAndrew Lunn 947fcd25166SAndrew Lunn static void mv88e6xxx_g2_watchdog_free(struct mv88e6xxx_chip *chip) 948fcd25166SAndrew Lunn { 949c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 950fcd25166SAndrew Lunn if (chip->info->ops->watchdog_ops->irq_free) 951fcd25166SAndrew Lunn chip->info->ops->watchdog_ops->irq_free(chip); 952c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 953fcd25166SAndrew Lunn 954fcd25166SAndrew Lunn free_irq(chip->watchdog_irq, chip); 955fcd25166SAndrew Lunn irq_dispose_mapping(chip->watchdog_irq); 956fcd25166SAndrew Lunn } 957fcd25166SAndrew Lunn 958fcd25166SAndrew Lunn static int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip) 959fcd25166SAndrew Lunn { 960fcd25166SAndrew Lunn int err; 961fcd25166SAndrew Lunn 962fcd25166SAndrew Lunn chip->watchdog_irq = irq_find_mapping(chip->g2_irq.domain, 9631d90016dSVivien Didelot MV88E6XXX_G2_INT_SOURCE_WATCHDOG); 964fcd25166SAndrew Lunn if (chip->watchdog_irq < 0) 965fcd25166SAndrew Lunn return chip->watchdog_irq; 966fcd25166SAndrew Lunn 9678b4db289SAndrew Lunn snprintf(chip->watchdog_irq_name, sizeof(chip->watchdog_irq_name), 9688b4db289SAndrew Lunn "mv88e6xxx-%s-watchdog", dev_name(chip->dev)); 9698b4db289SAndrew Lunn 970fcd25166SAndrew Lunn err = request_threaded_irq(chip->watchdog_irq, NULL, 971fcd25166SAndrew Lunn mv88e6xxx_g2_watchdog_thread_fn, 972fcd25166SAndrew Lunn IRQF_ONESHOT | IRQF_TRIGGER_FALLING, 9738b4db289SAndrew Lunn chip->watchdog_irq_name, chip); 974fcd25166SAndrew Lunn if (err) 975fcd25166SAndrew Lunn return err; 976fcd25166SAndrew Lunn 977c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 978fcd25166SAndrew Lunn if (chip->info->ops->watchdog_ops->irq_setup) 979fcd25166SAndrew Lunn err = chip->info->ops->watchdog_ops->irq_setup(chip); 980c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 981fcd25166SAndrew Lunn 982fcd25166SAndrew Lunn return err; 983fcd25166SAndrew Lunn } 984fcd25166SAndrew Lunn 98581228996SVivien Didelot /* Offset 0x1D: Misc Register */ 98681228996SVivien Didelot 98781228996SVivien Didelot static int mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip *chip, 98881228996SVivien Didelot bool port_5_bit) 98981228996SVivien Didelot { 99081228996SVivien Didelot u16 val; 99181228996SVivien Didelot int err; 99281228996SVivien Didelot 9931d90016dSVivien Didelot err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_MISC, &val); 99481228996SVivien Didelot if (err) 99581228996SVivien Didelot return err; 99681228996SVivien Didelot 99781228996SVivien Didelot if (port_5_bit) 9981d90016dSVivien Didelot val |= MV88E6XXX_G2_MISC_5_BIT_PORT; 99981228996SVivien Didelot else 10001d90016dSVivien Didelot val &= ~MV88E6XXX_G2_MISC_5_BIT_PORT; 100181228996SVivien Didelot 10021d90016dSVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MISC, val); 100381228996SVivien Didelot } 100481228996SVivien Didelot 100581228996SVivien Didelot int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip) 100681228996SVivien Didelot { 100781228996SVivien Didelot return mv88e6xxx_g2_misc_5_bit_port(chip, false); 100881228996SVivien Didelot } 100981228996SVivien Didelot 1010dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_mask(struct irq_data *d) 1011dc30c35bSAndrew Lunn { 1012dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 1013dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 1014dc30c35bSAndrew Lunn 1015dc30c35bSAndrew Lunn chip->g2_irq.masked |= (1 << n); 1016dc30c35bSAndrew Lunn } 1017dc30c35bSAndrew Lunn 1018dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_unmask(struct irq_data *d) 1019dc30c35bSAndrew Lunn { 1020dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 1021dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 1022dc30c35bSAndrew Lunn 1023dc30c35bSAndrew Lunn chip->g2_irq.masked &= ~(1 << n); 1024dc30c35bSAndrew Lunn } 1025dc30c35bSAndrew Lunn 1026dc30c35bSAndrew Lunn static irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id) 1027dc30c35bSAndrew Lunn { 1028dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = dev_id; 1029dc30c35bSAndrew Lunn unsigned int nhandled = 0; 1030dc30c35bSAndrew Lunn unsigned int sub_irq; 1031dc30c35bSAndrew Lunn unsigned int n; 1032dc30c35bSAndrew Lunn int err; 1033dc30c35bSAndrew Lunn u16 reg; 1034dc30c35bSAndrew Lunn 1035c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1036d6c5e6afSVivien Didelot err = mv88e6xxx_g2_int_source(chip, ®); 1037c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1038dc30c35bSAndrew Lunn if (err) 1039dc30c35bSAndrew Lunn goto out; 1040dc30c35bSAndrew Lunn 1041dc30c35bSAndrew Lunn for (n = 0; n < 16; ++n) { 1042dc30c35bSAndrew Lunn if (reg & (1 << n)) { 1043dc30c35bSAndrew Lunn sub_irq = irq_find_mapping(chip->g2_irq.domain, n); 1044dc30c35bSAndrew Lunn handle_nested_irq(sub_irq); 1045dc30c35bSAndrew Lunn ++nhandled; 1046dc30c35bSAndrew Lunn } 1047dc30c35bSAndrew Lunn } 1048dc30c35bSAndrew Lunn out: 1049dc30c35bSAndrew Lunn return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); 1050dc30c35bSAndrew Lunn } 1051dc30c35bSAndrew Lunn 1052dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_bus_lock(struct irq_data *d) 1053dc30c35bSAndrew Lunn { 1054dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 1055dc30c35bSAndrew Lunn 1056c9acece0SRasmus Villemoes mv88e6xxx_reg_lock(chip); 1057dc30c35bSAndrew Lunn } 1058dc30c35bSAndrew Lunn 1059dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d) 1060dc30c35bSAndrew Lunn { 1061dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 1062d6c5e6afSVivien Didelot int err; 1063dc30c35bSAndrew Lunn 1064d6c5e6afSVivien Didelot err = mv88e6xxx_g2_int_mask(chip, ~chip->g2_irq.masked); 1065d6c5e6afSVivien Didelot if (err) 1066d6c5e6afSVivien Didelot dev_err(chip->dev, "failed to mask interrupts\n"); 1067dc30c35bSAndrew Lunn 1068c9acece0SRasmus Villemoes mv88e6xxx_reg_unlock(chip); 1069dc30c35bSAndrew Lunn } 1070dc30c35bSAndrew Lunn 10716eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g2_irq_chip = { 1072dc30c35bSAndrew Lunn .name = "mv88e6xxx-g2", 1073dc30c35bSAndrew Lunn .irq_mask = mv88e6xxx_g2_irq_mask, 1074dc30c35bSAndrew Lunn .irq_unmask = mv88e6xxx_g2_irq_unmask, 1075dc30c35bSAndrew Lunn .irq_bus_lock = mv88e6xxx_g2_irq_bus_lock, 1076dc30c35bSAndrew Lunn .irq_bus_sync_unlock = mv88e6xxx_g2_irq_bus_sync_unlock, 1077dc30c35bSAndrew Lunn }; 1078dc30c35bSAndrew Lunn 1079dc30c35bSAndrew Lunn static int mv88e6xxx_g2_irq_domain_map(struct irq_domain *d, 1080dc30c35bSAndrew Lunn unsigned int irq, 1081dc30c35bSAndrew Lunn irq_hw_number_t hwirq) 1082dc30c35bSAndrew Lunn { 1083dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = d->host_data; 1084dc30c35bSAndrew Lunn 1085dc30c35bSAndrew Lunn irq_set_chip_data(irq, d->host_data); 1086dc30c35bSAndrew Lunn irq_set_chip_and_handler(irq, &chip->g2_irq.chip, handle_level_irq); 1087dc30c35bSAndrew Lunn irq_set_noprobe(irq); 1088dc30c35bSAndrew Lunn 1089dc30c35bSAndrew Lunn return 0; 1090dc30c35bSAndrew Lunn } 1091dc30c35bSAndrew Lunn 1092dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g2_irq_domain_ops = { 1093dc30c35bSAndrew Lunn .map = mv88e6xxx_g2_irq_domain_map, 1094dc30c35bSAndrew Lunn .xlate = irq_domain_xlate_twocell, 1095dc30c35bSAndrew Lunn }; 1096dc30c35bSAndrew Lunn 1097dc30c35bSAndrew Lunn void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip) 1098dc30c35bSAndrew Lunn { 1099dc30c35bSAndrew Lunn int irq, virq; 1100dc30c35bSAndrew Lunn 1101fcd25166SAndrew Lunn mv88e6xxx_g2_watchdog_free(chip); 1102fcd25166SAndrew Lunn 11038e757ebaSAndrew Lunn free_irq(chip->device_irq, chip); 11048e757ebaSAndrew Lunn irq_dispose_mapping(chip->device_irq); 11058e757ebaSAndrew Lunn 1106dc30c35bSAndrew Lunn for (irq = 0; irq < 16; irq++) { 1107dc30c35bSAndrew Lunn virq = irq_find_mapping(chip->g2_irq.domain, irq); 1108dc30c35bSAndrew Lunn irq_dispose_mapping(virq); 1109dc30c35bSAndrew Lunn } 1110dc30c35bSAndrew Lunn 1111dc30c35bSAndrew Lunn irq_domain_remove(chip->g2_irq.domain); 1112dc30c35bSAndrew Lunn } 1113dc30c35bSAndrew Lunn 1114dc30c35bSAndrew Lunn int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip) 1115dc30c35bSAndrew Lunn { 11168e757ebaSAndrew Lunn int err, irq, virq; 1117dc30c35bSAndrew Lunn 11180395823bSRussell King chip->g2_irq.masked = ~0; 11190395823bSRussell King mv88e6xxx_reg_lock(chip); 11200395823bSRussell King err = mv88e6xxx_g2_int_mask(chip, ~chip->g2_irq.masked); 11210395823bSRussell King mv88e6xxx_reg_unlock(chip); 11220395823bSRussell King if (err) 11230395823bSRussell King return err; 11240395823bSRussell King 1125dc30c35bSAndrew Lunn chip->g2_irq.domain = irq_domain_add_simple( 1126dc30c35bSAndrew Lunn chip->dev->of_node, 16, 0, &mv88e6xxx_g2_irq_domain_ops, chip); 1127dc30c35bSAndrew Lunn if (!chip->g2_irq.domain) 1128dc30c35bSAndrew Lunn return -ENOMEM; 1129dc30c35bSAndrew Lunn 1130dc30c35bSAndrew Lunn for (irq = 0; irq < 16; irq++) 1131dc30c35bSAndrew Lunn irq_create_mapping(chip->g2_irq.domain, irq); 1132dc30c35bSAndrew Lunn 1133dc30c35bSAndrew Lunn chip->g2_irq.chip = mv88e6xxx_g2_irq_chip; 1134dc30c35bSAndrew Lunn 11358e757ebaSAndrew Lunn chip->device_irq = irq_find_mapping(chip->g1_irq.domain, 113682466921SVivien Didelot MV88E6XXX_G1_STS_IRQ_DEVICE); 11378e757ebaSAndrew Lunn if (chip->device_irq < 0) { 11388e757ebaSAndrew Lunn err = chip->device_irq; 1139dc30c35bSAndrew Lunn goto out; 1140dc30c35bSAndrew Lunn } 1141dc30c35bSAndrew Lunn 114206acd114SAndrew Lunn snprintf(chip->device_irq_name, sizeof(chip->device_irq_name), 114306acd114SAndrew Lunn "mv88e6xxx-%s-g2", dev_name(chip->dev)); 114406acd114SAndrew Lunn 11458e757ebaSAndrew Lunn err = request_threaded_irq(chip->device_irq, NULL, 1146dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_thread_fn, 114706acd114SAndrew Lunn IRQF_ONESHOT, chip->device_irq_name, chip); 1148dc30c35bSAndrew Lunn if (err) 1149dc30c35bSAndrew Lunn goto out; 1150dc30c35bSAndrew Lunn 1151fcd25166SAndrew Lunn return mv88e6xxx_g2_watchdog_setup(chip); 11528e757ebaSAndrew Lunn 1153dc30c35bSAndrew Lunn out: 11548e757ebaSAndrew Lunn for (irq = 0; irq < 16; irq++) { 11558e757ebaSAndrew Lunn virq = irq_find_mapping(chip->g2_irq.domain, irq); 11568e757ebaSAndrew Lunn irq_dispose_mapping(virq); 11578e757ebaSAndrew Lunn } 11588e757ebaSAndrew Lunn 11598e757ebaSAndrew Lunn irq_domain_remove(chip->g2_irq.domain); 1160dc30c35bSAndrew Lunn 1161dc30c35bSAndrew Lunn return err; 1162dc30c35bSAndrew Lunn } 1163dc30c35bSAndrew Lunn 11646f88284fSAndrew Lunn int mv88e6xxx_g2_irq_mdio_setup(struct mv88e6xxx_chip *chip, 11656f88284fSAndrew Lunn struct mii_bus *bus) 11666f88284fSAndrew Lunn { 11676f88284fSAndrew Lunn int phy, irq, err, err_phy; 11686f88284fSAndrew Lunn 11696f88284fSAndrew Lunn for (phy = 0; phy < chip->info->num_internal_phys; phy++) { 11706f88284fSAndrew Lunn irq = irq_find_mapping(chip->g2_irq.domain, phy); 11716f88284fSAndrew Lunn if (irq < 0) { 11726f88284fSAndrew Lunn err = irq; 11736f88284fSAndrew Lunn goto out; 11746f88284fSAndrew Lunn } 11759255bacdSAndrew Lunn bus->irq[chip->info->phy_base_addr + phy] = irq; 11766f88284fSAndrew Lunn } 11776f88284fSAndrew Lunn return 0; 11786f88284fSAndrew Lunn out: 11796f88284fSAndrew Lunn err_phy = phy; 11806f88284fSAndrew Lunn 11816f88284fSAndrew Lunn for (phy = 0; phy < err_phy; phy++) 11826f88284fSAndrew Lunn irq_dispose_mapping(bus->irq[phy]); 11836f88284fSAndrew Lunn 11846f88284fSAndrew Lunn return err; 11856f88284fSAndrew Lunn } 11866f88284fSAndrew Lunn 11876f88284fSAndrew Lunn void mv88e6xxx_g2_irq_mdio_free(struct mv88e6xxx_chip *chip, 11886f88284fSAndrew Lunn struct mii_bus *bus) 11896f88284fSAndrew Lunn { 11906f88284fSAndrew Lunn int phy; 11916f88284fSAndrew Lunn 11926f88284fSAndrew Lunn for (phy = 0; phy < chip->info->num_internal_phys; phy++) 11936f88284fSAndrew Lunn irq_dispose_mapping(bus->irq[phy]); 11946f88284fSAndrew Lunn } 1195