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 29b000be95SBrandon Streiff int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update) 309fe850fbSVivien Didelot { 319069c13aSVivien Didelot return mv88e6xxx_update(chip, chip->info->global2_addr, reg, update); 329fe850fbSVivien Didelot } 339fe850fbSVivien Didelot 34b000be95SBrandon Streiff int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask) 359fe850fbSVivien Didelot { 369069c13aSVivien Didelot return mv88e6xxx_wait(chip, chip->info->global2_addr, reg, mask); 379fe850fbSVivien Didelot } 389fe850fbSVivien Didelot 39d6c5e6afSVivien Didelot /* Offset 0x00: Interrupt Source Register */ 40d6c5e6afSVivien Didelot 41d6c5e6afSVivien Didelot static int mv88e6xxx_g2_int_source(struct mv88e6xxx_chip *chip, u16 *src) 42d6c5e6afSVivien Didelot { 43d6c5e6afSVivien Didelot /* Read (and clear most of) the Interrupt Source bits */ 44d6c5e6afSVivien Didelot return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_INT_SRC, src); 45d6c5e6afSVivien Didelot } 46d6c5e6afSVivien Didelot 47d6c5e6afSVivien Didelot /* Offset 0x01: Interrupt Mask Register */ 48d6c5e6afSVivien Didelot 49d6c5e6afSVivien Didelot static int mv88e6xxx_g2_int_mask(struct mv88e6xxx_chip *chip, u16 mask) 50d6c5e6afSVivien Didelot { 51d6c5e6afSVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_INT_MASK, mask); 52d6c5e6afSVivien Didelot } 53d6c5e6afSVivien Didelot 546e55f698SAndrew Lunn /* Offset 0x02: Management Enable 2x */ 5551c901a7SVivien Didelot 5651c901a7SVivien Didelot static int mv88e6xxx_g2_mgmt_enable_2x(struct mv88e6xxx_chip *chip, u16 en2x) 5751c901a7SVivien Didelot { 5851c901a7SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_2X, en2x); 5951c901a7SVivien Didelot } 6051c901a7SVivien Didelot 616e55f698SAndrew Lunn /* Offset 0x03: Management Enable 0x */ 626e55f698SAndrew Lunn 6351c901a7SVivien Didelot static int mv88e6xxx_g2_mgmt_enable_0x(struct mv88e6xxx_chip *chip, u16 en0x) 6451c901a7SVivien Didelot { 6551c901a7SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_0X, en0x); 6651c901a7SVivien Didelot } 6751c901a7SVivien Didelot 6851c901a7SVivien Didelot /* Offset 0x05: Switch Management Register */ 6951c901a7SVivien Didelot 7051c901a7SVivien Didelot static int mv88e6xxx_g2_switch_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip, 7151c901a7SVivien Didelot bool enable) 7251c901a7SVivien Didelot { 7351c901a7SVivien Didelot u16 val; 7451c901a7SVivien Didelot int err; 7551c901a7SVivien Didelot 7651c901a7SVivien Didelot err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SWITCH_MGMT, &val); 7751c901a7SVivien Didelot if (err) 7851c901a7SVivien Didelot return err; 7951c901a7SVivien Didelot 8051c901a7SVivien Didelot if (enable) 8151c901a7SVivien Didelot val |= MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU; 8251c901a7SVivien Didelot else 8351c901a7SVivien Didelot val &= ~MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU; 8451c901a7SVivien Didelot 8551c901a7SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MGMT, val); 8651c901a7SVivien Didelot } 8751c901a7SVivien Didelot 8851c901a7SVivien Didelot int mv88e6185_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip) 8951c901a7SVivien Didelot { 9051c901a7SVivien Didelot int err; 9151c901a7SVivien Didelot 9251c901a7SVivien Didelot /* Consider the frames with reserved multicast destination 9351c901a7SVivien Didelot * addresses matching 01:80:c2:00:00:0x as MGMT. 9451c901a7SVivien Didelot */ 9551c901a7SVivien Didelot err = mv88e6xxx_g2_mgmt_enable_0x(chip, 0xffff); 9651c901a7SVivien Didelot if (err) 9751c901a7SVivien Didelot return err; 9851c901a7SVivien Didelot 9951c901a7SVivien Didelot return mv88e6xxx_g2_switch_mgmt_rsvd2cpu(chip, true); 10051c901a7SVivien Didelot } 10151c901a7SVivien Didelot 10251c901a7SVivien Didelot int mv88e6352_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip) 1036e55f698SAndrew Lunn { 1046e55f698SAndrew Lunn int err; 1056e55f698SAndrew Lunn 1066e55f698SAndrew Lunn /* Consider the frames with reserved multicast destination 1076e55f698SAndrew Lunn * addresses matching 01:80:c2:00:00:2x as MGMT. 1086e55f698SAndrew Lunn */ 10951c901a7SVivien Didelot err = mv88e6xxx_g2_mgmt_enable_2x(chip, 0xffff); 1106e55f698SAndrew Lunn if (err) 1116e55f698SAndrew Lunn return err; 1126e55f698SAndrew Lunn 11351c901a7SVivien Didelot return mv88e6185_g2_mgmt_rsvd2cpu(chip); 1146e55f698SAndrew Lunn } 1156e55f698SAndrew Lunn 116ec561276SVivien Didelot /* Offset 0x06: Device Mapping Table register */ 117ec561276SVivien Didelot 118c7f047b6SVivien Didelot int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target, 119c7f047b6SVivien Didelot int port) 120ec561276SVivien Didelot { 121c7f047b6SVivien Didelot u16 val = (target << 8) | (port & 0x1f); 122c7f047b6SVivien Didelot /* Modern chips use 5 bits to define a device mapping port, 123c7f047b6SVivien Didelot * but bit 4 is reserved on older chips, so it is safe to use. 124c7f047b6SVivien Didelot */ 125ec561276SVivien Didelot 126067e474aSVivien Didelot return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_DEVICE_MAPPING, val); 127ec561276SVivien Didelot } 128ec561276SVivien Didelot 129ec561276SVivien Didelot /* Offset 0x07: Trunk Mask Table register */ 130ec561276SVivien Didelot 131ec561276SVivien Didelot static int mv88e6xxx_g2_trunk_mask_write(struct mv88e6xxx_chip *chip, int num, 13256dc7347SVivien Didelot bool hash, u16 mask) 133ec561276SVivien Didelot { 13456dc7347SVivien Didelot u16 val = (num << 12) | (mask & mv88e6xxx_port_mask(chip)); 135ec561276SVivien Didelot 13656dc7347SVivien Didelot if (hash) 13756dc7347SVivien Didelot val |= MV88E6XXX_G2_TRUNK_MASK_HASH; 138ec561276SVivien Didelot 13956dc7347SVivien Didelot return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_TRUNK_MASK, val); 140ec561276SVivien Didelot } 141ec561276SVivien Didelot 142ec561276SVivien Didelot /* Offset 0x08: Trunk Mapping Table register */ 143ec561276SVivien Didelot 144ec561276SVivien Didelot static int mv88e6xxx_g2_trunk_mapping_write(struct mv88e6xxx_chip *chip, int id, 145ec561276SVivien Didelot u16 map) 146ec561276SVivien Didelot { 147370b4ffbSVivien Didelot const u16 port_mask = BIT(mv88e6xxx_num_ports(chip)) - 1; 148ec561276SVivien Didelot u16 val = (id << 11) | (map & port_mask); 149ec561276SVivien Didelot 15056dc7347SVivien Didelot return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_TRUNK_MAPPING, 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 { 181cd8da8bbSVivien Didelot return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_IRL_CMD, 182cd8da8bbSVivien Didelot MV88E6XXX_G2_IRL_CMD_BUSY); 183ec561276SVivien Didelot } 184ec561276SVivien Didelot 185cd8da8bbSVivien Didelot static int mv88e6xxx_g2_irl_op(struct mv88e6xxx_chip *chip, u16 op, int port, 186cd8da8bbSVivien Didelot int res, int reg) 187cd8da8bbSVivien Didelot { 188cd8da8bbSVivien Didelot int err; 189cd8da8bbSVivien Didelot 190cd8da8bbSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_IRL_CMD, 191cd8da8bbSVivien Didelot MV88E6XXX_G2_IRL_CMD_BUSY | op | (port << 8) | 192cd8da8bbSVivien Didelot (res << 5) | reg); 193cd8da8bbSVivien Didelot if (err) 194ec561276SVivien Didelot return err; 195cd8da8bbSVivien Didelot 196cd8da8bbSVivien Didelot return mv88e6xxx_g2_irl_wait(chip); 197cd8da8bbSVivien Didelot } 198cd8da8bbSVivien Didelot 199cd8da8bbSVivien Didelot int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port) 200cd8da8bbSVivien Didelot { 201cd8da8bbSVivien Didelot return mv88e6xxx_g2_irl_op(chip, MV88E6352_G2_IRL_CMD_OP_INIT_ALL, port, 202cd8da8bbSVivien Didelot 0, 0); 203cd8da8bbSVivien Didelot } 204cd8da8bbSVivien Didelot 205cd8da8bbSVivien Didelot int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port) 206cd8da8bbSVivien Didelot { 207cd8da8bbSVivien Didelot return mv88e6xxx_g2_irl_op(chip, MV88E6390_G2_IRL_CMD_OP_INIT_ALL, port, 208cd8da8bbSVivien Didelot 0, 0); 209ec561276SVivien Didelot } 210ec561276SVivien Didelot 21117a1594eSVivien Didelot /* Offset 0x0B: Cross-chip Port VLAN (Addr) Register 21217a1594eSVivien Didelot * Offset 0x0C: Cross-chip Port VLAN Data Register 21317a1594eSVivien Didelot */ 21417a1594eSVivien Didelot 21517a1594eSVivien Didelot static int mv88e6xxx_g2_pvt_op_wait(struct mv88e6xxx_chip *chip) 21617a1594eSVivien Didelot { 21767d1ea8eSVivien Didelot return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_PVT_ADDR, 21867d1ea8eSVivien Didelot MV88E6XXX_G2_PVT_ADDR_BUSY); 21917a1594eSVivien Didelot } 22017a1594eSVivien Didelot 22117a1594eSVivien Didelot static int mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip *chip, int src_dev, 22217a1594eSVivien Didelot int src_port, u16 op) 22317a1594eSVivien Didelot { 22417a1594eSVivien Didelot int err; 22517a1594eSVivien Didelot 22667d1ea8eSVivien Didelot /* 9-bit Cross-chip PVT pointer: with MV88E6XXX_G2_MISC_5_BIT_PORT 22767d1ea8eSVivien Didelot * cleared, source device is 5-bit, source port is 4-bit. 22817a1594eSVivien Didelot */ 22967d1ea8eSVivien Didelot op |= MV88E6XXX_G2_PVT_ADDR_BUSY; 23017a1594eSVivien Didelot op |= (src_dev & 0x1f) << 4; 23117a1594eSVivien Didelot op |= (src_port & 0xf); 23217a1594eSVivien Didelot 23367d1ea8eSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_ADDR, op); 23417a1594eSVivien Didelot if (err) 23517a1594eSVivien Didelot return err; 23617a1594eSVivien Didelot 23717a1594eSVivien Didelot return mv88e6xxx_g2_pvt_op_wait(chip); 23817a1594eSVivien Didelot } 23917a1594eSVivien Didelot 24017a1594eSVivien Didelot int mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev, 24117a1594eSVivien Didelot int src_port, u16 data) 24217a1594eSVivien Didelot { 24317a1594eSVivien Didelot int err; 24417a1594eSVivien Didelot 24517a1594eSVivien Didelot err = mv88e6xxx_g2_pvt_op_wait(chip); 24617a1594eSVivien Didelot if (err) 24717a1594eSVivien Didelot return err; 24817a1594eSVivien Didelot 24967d1ea8eSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_PVT_DATA, data); 25017a1594eSVivien Didelot if (err) 25117a1594eSVivien Didelot return err; 25217a1594eSVivien Didelot 25317a1594eSVivien Didelot return mv88e6xxx_g2_pvt_op(chip, src_dev, src_port, 25467d1ea8eSVivien Didelot MV88E6XXX_G2_PVT_ADDR_OP_WRITE_PVLAN); 25517a1594eSVivien Didelot } 25617a1594eSVivien Didelot 257ec561276SVivien Didelot /* Offset 0x0D: Switch MAC/WoL/WoF register */ 258ec561276SVivien Didelot 259ec561276SVivien Didelot static int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip, 260ec561276SVivien Didelot unsigned int pointer, u8 data) 261ec561276SVivien Didelot { 262ec561276SVivien Didelot u16 val = (pointer << 8) | data; 263ec561276SVivien Didelot 264ed44152fSVivien Didelot return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_SWITCH_MAC, val); 265ec561276SVivien Didelot } 266ec561276SVivien Didelot 267ec561276SVivien Didelot int mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) 268ec561276SVivien Didelot { 269ec561276SVivien Didelot int i, err; 270ec561276SVivien Didelot 271ec561276SVivien Didelot for (i = 0; i < 6; i++) { 272ec561276SVivien Didelot err = mv88e6xxx_g2_switch_mac_write(chip, i, addr[i]); 273ec561276SVivien Didelot if (err) 274ec561276SVivien Didelot break; 275ec561276SVivien Didelot } 276ec561276SVivien Didelot 277ec561276SVivien Didelot return err; 278ec561276SVivien Didelot } 279ec561276SVivien Didelot 280ec561276SVivien Didelot /* Offset 0x0F: Priority Override Table */ 281ec561276SVivien Didelot 282ec561276SVivien Didelot static int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer, 283ec561276SVivien Didelot u8 data) 284ec561276SVivien Didelot { 285ec561276SVivien Didelot u16 val = (pointer << 8) | (data & 0x7); 286ec561276SVivien Didelot 2871d90016dSVivien Didelot return mv88e6xxx_g2_update(chip, MV88E6XXX_G2_PRIO_OVERRIDE, val); 288ec561276SVivien Didelot } 289ec561276SVivien Didelot 2909e907d73SVivien Didelot int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip) 291ec561276SVivien Didelot { 292ec561276SVivien Didelot int i, err; 293ec561276SVivien Didelot 294ec561276SVivien Didelot /* Clear all sixteen possible Priority Override entries */ 295ec561276SVivien Didelot for (i = 0; i < 16; i++) { 296ec561276SVivien Didelot err = mv88e6xxx_g2_pot_write(chip, i, 0); 297ec561276SVivien Didelot if (err) 298ec561276SVivien Didelot break; 299ec561276SVivien Didelot } 300ec561276SVivien Didelot 301ec561276SVivien Didelot return err; 302ec561276SVivien Didelot } 303ec561276SVivien Didelot 304ec561276SVivien Didelot /* Offset 0x14: EEPROM Command 30598fc3c6fSVivien Didelot * Offset 0x15: EEPROM Data (for 16-bit data access) 30698fc3c6fSVivien Didelot * Offset 0x15: EEPROM Addr (for 8-bit data access) 307ec561276SVivien Didelot */ 308ec561276SVivien Didelot 309ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip) 310ec561276SVivien Didelot { 3117fc8c9d5SVivien Didelot return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_EEPROM_CMD, 3127fc8c9d5SVivien Didelot MV88E6XXX_G2_EEPROM_CMD_BUSY | 3137fc8c9d5SVivien Didelot MV88E6XXX_G2_EEPROM_CMD_RUNNING); 314ec561276SVivien Didelot } 315ec561276SVivien Didelot 316ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd) 317ec561276SVivien Didelot { 318ec561276SVivien Didelot int err; 319ec561276SVivien Didelot 3207fc8c9d5SVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_EEPROM_CMD, 3217fc8c9d5SVivien Didelot MV88E6XXX_G2_EEPROM_CMD_BUSY | cmd); 322ec561276SVivien Didelot if (err) 323ec561276SVivien Didelot return err; 324ec561276SVivien Didelot 325ec561276SVivien Didelot return mv88e6xxx_g2_eeprom_wait(chip); 326ec561276SVivien Didelot } 327ec561276SVivien Didelot 32898fc3c6fSVivien Didelot static int mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip *chip, 32998fc3c6fSVivien Didelot u16 addr, u8 *data) 33098fc3c6fSVivien Didelot { 3317fc8c9d5SVivien Didelot u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ; 33298fc3c6fSVivien Didelot int err; 33398fc3c6fSVivien Didelot 33498fc3c6fSVivien Didelot err = mv88e6xxx_g2_eeprom_wait(chip); 33598fc3c6fSVivien Didelot if (err) 33698fc3c6fSVivien Didelot return err; 33798fc3c6fSVivien Didelot 3387fc8c9d5SVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr); 33998fc3c6fSVivien Didelot if (err) 34098fc3c6fSVivien Didelot return err; 34198fc3c6fSVivien Didelot 34298fc3c6fSVivien Didelot err = mv88e6xxx_g2_eeprom_cmd(chip, cmd); 34398fc3c6fSVivien Didelot if (err) 34498fc3c6fSVivien Didelot return err; 34598fc3c6fSVivien Didelot 3467fc8c9d5SVivien Didelot err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &cmd); 34798fc3c6fSVivien Didelot if (err) 34898fc3c6fSVivien Didelot return err; 34998fc3c6fSVivien Didelot 35098fc3c6fSVivien Didelot *data = cmd & 0xff; 35198fc3c6fSVivien Didelot 35298fc3c6fSVivien Didelot return 0; 35398fc3c6fSVivien Didelot } 35498fc3c6fSVivien Didelot 35598fc3c6fSVivien Didelot static int mv88e6xxx_g2_eeprom_write8(struct mv88e6xxx_chip *chip, 35698fc3c6fSVivien Didelot u16 addr, u8 data) 35798fc3c6fSVivien Didelot { 3587fc8c9d5SVivien Didelot u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE | 3597fc8c9d5SVivien Didelot MV88E6XXX_G2_EEPROM_CMD_WRITE_EN; 36098fc3c6fSVivien Didelot int err; 36198fc3c6fSVivien Didelot 36298fc3c6fSVivien Didelot err = mv88e6xxx_g2_eeprom_wait(chip); 36398fc3c6fSVivien Didelot if (err) 36498fc3c6fSVivien Didelot return err; 36598fc3c6fSVivien Didelot 3667fc8c9d5SVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr); 36798fc3c6fSVivien Didelot if (err) 36898fc3c6fSVivien Didelot return err; 36998fc3c6fSVivien Didelot 37098fc3c6fSVivien Didelot return mv88e6xxx_g2_eeprom_cmd(chip, cmd | data); 37198fc3c6fSVivien Didelot } 37298fc3c6fSVivien Didelot 373ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip, 374ec561276SVivien Didelot u8 addr, u16 *data) 375ec561276SVivien Didelot { 3767fc8c9d5SVivien Didelot u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ | addr; 377ec561276SVivien Didelot int err; 378ec561276SVivien Didelot 379ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_wait(chip); 380ec561276SVivien Didelot if (err) 381ec561276SVivien Didelot return err; 382ec561276SVivien Didelot 383ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_cmd(chip, cmd); 384ec561276SVivien Didelot if (err) 385ec561276SVivien Didelot return err; 386ec561276SVivien Didelot 3877fc8c9d5SVivien Didelot return mv88e6xxx_g2_read(chip, MV88E6352_G2_EEPROM_DATA, data); 388ec561276SVivien Didelot } 389ec561276SVivien Didelot 390ec561276SVivien Didelot static int mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip *chip, 391ec561276SVivien Didelot u8 addr, u16 data) 392ec561276SVivien Didelot { 3937fc8c9d5SVivien Didelot u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE | addr; 394ec561276SVivien Didelot int err; 395ec561276SVivien Didelot 396ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_wait(chip); 397ec561276SVivien Didelot if (err) 398ec561276SVivien Didelot return err; 399ec561276SVivien Didelot 4007fc8c9d5SVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6352_G2_EEPROM_DATA, data); 401ec561276SVivien Didelot if (err) 402ec561276SVivien Didelot return err; 403ec561276SVivien Didelot 404ec561276SVivien Didelot return mv88e6xxx_g2_eeprom_cmd(chip, cmd); 405ec561276SVivien Didelot } 406ec561276SVivien Didelot 40798fc3c6fSVivien Didelot int mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip *chip, 40898fc3c6fSVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 40998fc3c6fSVivien Didelot { 41098fc3c6fSVivien Didelot unsigned int offset = eeprom->offset; 41198fc3c6fSVivien Didelot unsigned int len = eeprom->len; 41298fc3c6fSVivien Didelot int err; 41398fc3c6fSVivien Didelot 41498fc3c6fSVivien Didelot eeprom->len = 0; 41598fc3c6fSVivien Didelot 41698fc3c6fSVivien Didelot while (len) { 41798fc3c6fSVivien Didelot err = mv88e6xxx_g2_eeprom_read8(chip, offset, data); 41898fc3c6fSVivien Didelot if (err) 41998fc3c6fSVivien Didelot return err; 42098fc3c6fSVivien Didelot 42198fc3c6fSVivien Didelot eeprom->len++; 42298fc3c6fSVivien Didelot offset++; 42398fc3c6fSVivien Didelot data++; 42498fc3c6fSVivien Didelot len--; 42598fc3c6fSVivien Didelot } 42698fc3c6fSVivien Didelot 42798fc3c6fSVivien Didelot return 0; 42898fc3c6fSVivien Didelot } 42998fc3c6fSVivien Didelot 43098fc3c6fSVivien Didelot int mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip *chip, 43198fc3c6fSVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 43298fc3c6fSVivien Didelot { 43398fc3c6fSVivien Didelot unsigned int offset = eeprom->offset; 43498fc3c6fSVivien Didelot unsigned int len = eeprom->len; 43598fc3c6fSVivien Didelot int err; 43698fc3c6fSVivien Didelot 43798fc3c6fSVivien Didelot eeprom->len = 0; 43898fc3c6fSVivien Didelot 43998fc3c6fSVivien Didelot while (len) { 44098fc3c6fSVivien Didelot err = mv88e6xxx_g2_eeprom_write8(chip, offset, *data); 44198fc3c6fSVivien Didelot if (err) 44298fc3c6fSVivien Didelot return err; 44398fc3c6fSVivien Didelot 44498fc3c6fSVivien Didelot eeprom->len++; 44598fc3c6fSVivien Didelot offset++; 44698fc3c6fSVivien Didelot data++; 44798fc3c6fSVivien Didelot len--; 44898fc3c6fSVivien Didelot } 44998fc3c6fSVivien Didelot 45098fc3c6fSVivien Didelot return 0; 45198fc3c6fSVivien Didelot } 45298fc3c6fSVivien Didelot 453ec561276SVivien Didelot int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip, 454ec561276SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 455ec561276SVivien Didelot { 456ec561276SVivien Didelot unsigned int offset = eeprom->offset; 457ec561276SVivien Didelot unsigned int len = eeprom->len; 458ec561276SVivien Didelot u16 val; 459ec561276SVivien Didelot int err; 460ec561276SVivien Didelot 461ec561276SVivien Didelot eeprom->len = 0; 462ec561276SVivien Didelot 463ec561276SVivien Didelot if (offset & 1) { 464ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val); 465ec561276SVivien Didelot if (err) 466ec561276SVivien Didelot return err; 467ec561276SVivien Didelot 468ec561276SVivien Didelot *data++ = (val >> 8) & 0xff; 469ec561276SVivien Didelot 470ec561276SVivien Didelot offset++; 471ec561276SVivien Didelot len--; 472ec561276SVivien Didelot eeprom->len++; 473ec561276SVivien Didelot } 474ec561276SVivien Didelot 475ec561276SVivien Didelot while (len >= 2) { 476ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val); 477ec561276SVivien Didelot if (err) 478ec561276SVivien Didelot return err; 479ec561276SVivien Didelot 480ec561276SVivien Didelot *data++ = val & 0xff; 481ec561276SVivien Didelot *data++ = (val >> 8) & 0xff; 482ec561276SVivien Didelot 483ec561276SVivien Didelot offset += 2; 484ec561276SVivien Didelot len -= 2; 485ec561276SVivien Didelot eeprom->len += 2; 486ec561276SVivien Didelot } 487ec561276SVivien Didelot 488ec561276SVivien Didelot if (len) { 489ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val); 490ec561276SVivien Didelot if (err) 491ec561276SVivien Didelot return err; 492ec561276SVivien Didelot 493ec561276SVivien Didelot *data++ = val & 0xff; 494ec561276SVivien Didelot 495ec561276SVivien Didelot offset++; 496ec561276SVivien Didelot len--; 497ec561276SVivien Didelot eeprom->len++; 498ec561276SVivien Didelot } 499ec561276SVivien Didelot 500ec561276SVivien Didelot return 0; 501ec561276SVivien Didelot } 502ec561276SVivien Didelot 503ec561276SVivien Didelot int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip, 504ec561276SVivien Didelot struct ethtool_eeprom *eeprom, u8 *data) 505ec561276SVivien Didelot { 506ec561276SVivien Didelot unsigned int offset = eeprom->offset; 507ec561276SVivien Didelot unsigned int len = eeprom->len; 508ec561276SVivien Didelot u16 val; 509ec561276SVivien Didelot int err; 510ec561276SVivien Didelot 511ec561276SVivien Didelot /* Ensure the RO WriteEn bit is set */ 5127fc8c9d5SVivien Didelot err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &val); 513ec561276SVivien Didelot if (err) 514ec561276SVivien Didelot return err; 515ec561276SVivien Didelot 5167fc8c9d5SVivien Didelot if (!(val & MV88E6XXX_G2_EEPROM_CMD_WRITE_EN)) 517ec561276SVivien Didelot return -EROFS; 518ec561276SVivien Didelot 519ec561276SVivien Didelot eeprom->len = 0; 520ec561276SVivien Didelot 521ec561276SVivien Didelot if (offset & 1) { 522ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val); 523ec561276SVivien Didelot if (err) 524ec561276SVivien Didelot return err; 525ec561276SVivien Didelot 526ec561276SVivien Didelot val = (*data++ << 8) | (val & 0xff); 527ec561276SVivien Didelot 528ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val); 529ec561276SVivien Didelot if (err) 530ec561276SVivien Didelot return err; 531ec561276SVivien Didelot 532ec561276SVivien Didelot offset++; 533ec561276SVivien Didelot len--; 534ec561276SVivien Didelot eeprom->len++; 535ec561276SVivien Didelot } 536ec561276SVivien Didelot 537ec561276SVivien Didelot while (len >= 2) { 538ec561276SVivien Didelot val = *data++; 539ec561276SVivien Didelot val |= *data++ << 8; 540ec561276SVivien Didelot 541ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val); 542ec561276SVivien Didelot if (err) 543ec561276SVivien Didelot return err; 544ec561276SVivien Didelot 545ec561276SVivien Didelot offset += 2; 546ec561276SVivien Didelot len -= 2; 547ec561276SVivien Didelot eeprom->len += 2; 548ec561276SVivien Didelot } 549ec561276SVivien Didelot 550ec561276SVivien Didelot if (len) { 551ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val); 552ec561276SVivien Didelot if (err) 553ec561276SVivien Didelot return err; 554ec561276SVivien Didelot 555ec561276SVivien Didelot val = (val & 0xff00) | *data++; 556ec561276SVivien Didelot 557ec561276SVivien Didelot err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val); 558ec561276SVivien Didelot if (err) 559ec561276SVivien Didelot return err; 560ec561276SVivien Didelot 561ec561276SVivien Didelot offset++; 562ec561276SVivien Didelot len--; 563ec561276SVivien Didelot eeprom->len++; 564ec561276SVivien Didelot } 565ec561276SVivien Didelot 566ec561276SVivien Didelot return 0; 567ec561276SVivien Didelot } 568ec561276SVivien Didelot 569ec561276SVivien Didelot /* Offset 0x18: SMI PHY Command Register 570ec561276SVivien Didelot * Offset 0x19: SMI PHY Data Register 571ec561276SVivien Didelot */ 572ec561276SVivien Didelot 573ec561276SVivien Didelot static int mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip *chip) 574ec561276SVivien Didelot { 575e289ef0dSVivien Didelot return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_SMI_PHY_CMD, 576e289ef0dSVivien Didelot MV88E6XXX_G2_SMI_PHY_CMD_BUSY); 577ec561276SVivien Didelot } 578ec561276SVivien Didelot 579ec561276SVivien Didelot static int mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip *chip, u16 cmd) 580ec561276SVivien Didelot { 581ec561276SVivien Didelot int err; 582ec561276SVivien Didelot 583e289ef0dSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_CMD, 584e289ef0dSVivien Didelot MV88E6XXX_G2_SMI_PHY_CMD_BUSY | cmd); 585ec561276SVivien Didelot if (err) 586ec561276SVivien Didelot return err; 587ec561276SVivien Didelot 588ec561276SVivien Didelot return mv88e6xxx_g2_smi_phy_wait(chip); 589ec561276SVivien Didelot } 590ec561276SVivien Didelot 591e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_access(struct mv88e6xxx_chip *chip, 592e289ef0dSVivien Didelot bool external, bool c45, u16 op, int dev, 593e289ef0dSVivien Didelot int reg) 594ec561276SVivien Didelot { 595e289ef0dSVivien Didelot u16 cmd = op; 596ec561276SVivien Didelot 597cf3e80dfSAndrew Lunn if (external) 598e289ef0dSVivien Didelot cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_EXTERNAL; 599e289ef0dSVivien Didelot else 600e289ef0dSVivien Didelot cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_INTERNAL; /* empty mask */ 601cf3e80dfSAndrew Lunn 602e289ef0dSVivien Didelot if (c45) 603e289ef0dSVivien Didelot cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_45; /* empty mask */ 604e289ef0dSVivien Didelot else 605e289ef0dSVivien Didelot cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_22; 606cf3e80dfSAndrew Lunn 607e289ef0dSVivien Didelot dev <<= __bf_shf(MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK); 608e289ef0dSVivien Didelot cmd |= dev & MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK; 609e289ef0dSVivien Didelot cmd |= reg & MV88E6XXX_G2_SMI_PHY_CMD_REG_ADDR_MASK; 610cf3e80dfSAndrew Lunn 611cf3e80dfSAndrew Lunn return mv88e6xxx_g2_smi_phy_cmd(chip, cmd); 612cf3e80dfSAndrew Lunn } 613cf3e80dfSAndrew Lunn 614e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_access_c22(struct mv88e6xxx_chip *chip, 615e289ef0dSVivien Didelot bool external, u16 op, int dev, 616e289ef0dSVivien Didelot int reg) 617cf3e80dfSAndrew Lunn { 618e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_access(chip, external, false, op, dev, reg); 619cf3e80dfSAndrew Lunn } 620cf3e80dfSAndrew Lunn 621e289ef0dSVivien Didelot /* IEEE 802.3 Clause 22 Read Data Register */ 622e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_read_data_c22(struct mv88e6xxx_chip *chip, 623e289ef0dSVivien Didelot bool external, int dev, int reg, 624e289ef0dSVivien Didelot u16 *data) 625cf3e80dfSAndrew Lunn { 626e289ef0dSVivien Didelot u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_READ_DATA; 627cf3e80dfSAndrew Lunn int err; 628cf3e80dfSAndrew Lunn 629ec561276SVivien Didelot err = mv88e6xxx_g2_smi_phy_wait(chip); 630ec561276SVivien Didelot if (err) 631ec561276SVivien Didelot return err; 632ec561276SVivien Didelot 633e289ef0dSVivien Didelot err = mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg); 634ec561276SVivien Didelot if (err) 635ec561276SVivien Didelot return err; 636ec561276SVivien Didelot 637e289ef0dSVivien Didelot return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data); 638ec561276SVivien Didelot } 639ec561276SVivien Didelot 640e289ef0dSVivien Didelot /* IEEE 802.3 Clause 22 Write Data Register */ 641e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_data_c22(struct mv88e6xxx_chip *chip, 642e289ef0dSVivien Didelot bool external, int dev, int reg, 643e289ef0dSVivien Didelot u16 data) 644e289ef0dSVivien Didelot { 645e289ef0dSVivien Didelot u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_WRITE_DATA; 646e289ef0dSVivien Didelot int err; 647e289ef0dSVivien Didelot 648e289ef0dSVivien Didelot err = mv88e6xxx_g2_smi_phy_wait(chip); 649e289ef0dSVivien Didelot if (err) 650e289ef0dSVivien Didelot return err; 651e289ef0dSVivien Didelot 652e289ef0dSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data); 653e289ef0dSVivien Didelot if (err) 654e289ef0dSVivien Didelot return err; 655e289ef0dSVivien Didelot 656e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg); 657e289ef0dSVivien Didelot } 658e289ef0dSVivien Didelot 659e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_access_c45(struct mv88e6xxx_chip *chip, 660e289ef0dSVivien Didelot bool external, u16 op, int port, 661e289ef0dSVivien Didelot int dev) 662e289ef0dSVivien Didelot { 663e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_access(chip, external, true, op, port, dev); 664e289ef0dSVivien Didelot } 665e289ef0dSVivien Didelot 666e289ef0dSVivien Didelot /* IEEE 802.3 Clause 45 Write Address Register */ 667e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_addr_c45(struct mv88e6xxx_chip *chip, 668e289ef0dSVivien Didelot bool external, int port, int dev, 669e289ef0dSVivien Didelot int addr) 670e289ef0dSVivien Didelot { 671e289ef0dSVivien Didelot u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_ADDR; 672e289ef0dSVivien Didelot int err; 673e289ef0dSVivien Didelot 674e289ef0dSVivien Didelot err = mv88e6xxx_g2_smi_phy_wait(chip); 675e289ef0dSVivien Didelot if (err) 676e289ef0dSVivien Didelot return err; 677e289ef0dSVivien Didelot 678e289ef0dSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, addr); 679e289ef0dSVivien Didelot if (err) 680e289ef0dSVivien Didelot return err; 681e289ef0dSVivien Didelot 682e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev); 683e289ef0dSVivien Didelot } 684e289ef0dSVivien Didelot 685e289ef0dSVivien Didelot /* IEEE 802.3 Clause 45 Read Data Register */ 686e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_read_data_c45(struct mv88e6xxx_chip *chip, 687e289ef0dSVivien Didelot bool external, int port, int dev, 688e289ef0dSVivien Didelot u16 *data) 689e289ef0dSVivien Didelot { 690e289ef0dSVivien Didelot u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_READ_DATA; 691e289ef0dSVivien Didelot int err; 692e289ef0dSVivien Didelot 693e289ef0dSVivien Didelot err = mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev); 694e289ef0dSVivien Didelot if (err) 695e289ef0dSVivien Didelot return err; 696e289ef0dSVivien Didelot 697e289ef0dSVivien Didelot return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data); 698e289ef0dSVivien Didelot } 699e289ef0dSVivien Didelot 700e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip, 701e289ef0dSVivien Didelot bool external, int port, int reg, 702e289ef0dSVivien Didelot u16 *data) 703e289ef0dSVivien Didelot { 704e289ef0dSVivien Didelot int dev = (reg >> 16) & 0x1f; 705e289ef0dSVivien Didelot int addr = reg & 0xffff; 706e289ef0dSVivien Didelot int err; 707e289ef0dSVivien Didelot 708e289ef0dSVivien Didelot err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev, 709e289ef0dSVivien Didelot addr); 710e289ef0dSVivien Didelot if (err) 711e289ef0dSVivien Didelot return err; 712e289ef0dSVivien Didelot 713e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_read_data_c45(chip, external, port, dev, 714e289ef0dSVivien Didelot data); 715e289ef0dSVivien Didelot } 716e289ef0dSVivien Didelot 717e289ef0dSVivien Didelot /* IEEE 802.3 Clause 45 Write Data Register */ 718e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_data_c45(struct mv88e6xxx_chip *chip, 719e289ef0dSVivien Didelot bool external, int port, int dev, 720e289ef0dSVivien Didelot u16 data) 721e289ef0dSVivien Didelot { 722e289ef0dSVivien Didelot u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_DATA; 723e289ef0dSVivien Didelot int err; 724e289ef0dSVivien Didelot 725e289ef0dSVivien Didelot err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data); 726e289ef0dSVivien Didelot if (err) 727e289ef0dSVivien Didelot return err; 728e289ef0dSVivien Didelot 729e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_access_c45(chip, external, op, port, dev); 730e289ef0dSVivien Didelot } 731e289ef0dSVivien Didelot 732e289ef0dSVivien Didelot static int mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip, 733e289ef0dSVivien Didelot bool external, int port, int reg, 734e289ef0dSVivien Didelot u16 data) 735e289ef0dSVivien Didelot { 736e289ef0dSVivien Didelot int dev = (reg >> 16) & 0x1f; 737e289ef0dSVivien Didelot int addr = reg & 0xffff; 738e289ef0dSVivien Didelot int err; 739e289ef0dSVivien Didelot 740e289ef0dSVivien Didelot err = mv88e6xxx_g2_smi_phy_write_addr_c45(chip, external, port, dev, 741e289ef0dSVivien Didelot addr); 742e289ef0dSVivien Didelot if (err) 743e289ef0dSVivien Didelot return err; 744e289ef0dSVivien Didelot 745e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_write_data_c45(chip, external, port, dev, 746e289ef0dSVivien Didelot data); 747e289ef0dSVivien Didelot } 748e289ef0dSVivien Didelot 749e289ef0dSVivien Didelot int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus, 750cf3e80dfSAndrew Lunn int addr, int reg, u16 *val) 751cf3e80dfSAndrew Lunn { 752cf3e80dfSAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 753cf3e80dfSAndrew Lunn bool external = mdio_bus->external; 754cf3e80dfSAndrew Lunn 755cf3e80dfSAndrew Lunn if (reg & MII_ADDR_C45) 756e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_read_c45(chip, external, addr, reg, 757e289ef0dSVivien Didelot val); 758e289ef0dSVivien Didelot 759e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_read_data_c22(chip, external, addr, reg, 760e289ef0dSVivien Didelot val); 761cf3e80dfSAndrew Lunn } 762cf3e80dfSAndrew Lunn 763e289ef0dSVivien Didelot int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus, 764cf3e80dfSAndrew Lunn int addr, int reg, u16 val) 765cf3e80dfSAndrew Lunn { 766cf3e80dfSAndrew Lunn struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 767cf3e80dfSAndrew Lunn bool external = mdio_bus->external; 768cf3e80dfSAndrew Lunn 769cf3e80dfSAndrew Lunn if (reg & MII_ADDR_C45) 770e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_write_c45(chip, external, addr, reg, 771e289ef0dSVivien Didelot val); 772cf3e80dfSAndrew Lunn 773e289ef0dSVivien Didelot return mv88e6xxx_g2_smi_phy_write_data_c22(chip, external, addr, reg, 774e289ef0dSVivien Didelot val); 775cf3e80dfSAndrew Lunn } 776cf3e80dfSAndrew Lunn 777a73ccd61SBrandon Streiff /* Offset 0x1B: Watchdog Control */ 778fcd25166SAndrew Lunn static int mv88e6097_watchdog_action(struct mv88e6xxx_chip *chip, int irq) 779fcd25166SAndrew Lunn { 780fcd25166SAndrew Lunn u16 reg; 781fcd25166SAndrew Lunn 7823b19df73SVivien Didelot mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, ®); 783fcd25166SAndrew Lunn 784fcd25166SAndrew Lunn dev_info(chip->dev, "Watchdog event: 0x%04x", reg); 785fcd25166SAndrew Lunn 786fcd25166SAndrew Lunn return IRQ_HANDLED; 787fcd25166SAndrew Lunn } 788fcd25166SAndrew Lunn 789fcd25166SAndrew Lunn static void mv88e6097_watchdog_free(struct mv88e6xxx_chip *chip) 790fcd25166SAndrew Lunn { 791fcd25166SAndrew Lunn u16 reg; 792fcd25166SAndrew Lunn 7933b19df73SVivien Didelot mv88e6xxx_g2_read(chip, MV88E6352_G2_WDOG_CTL, ®); 794fcd25166SAndrew Lunn 7953b19df73SVivien Didelot reg &= ~(MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE | 7963b19df73SVivien Didelot MV88E6352_G2_WDOG_CTL_QC_ENABLE); 797fcd25166SAndrew Lunn 7983b19df73SVivien Didelot mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL, reg); 799fcd25166SAndrew Lunn } 800fcd25166SAndrew Lunn 801fcd25166SAndrew Lunn static int mv88e6097_watchdog_setup(struct mv88e6xxx_chip *chip) 802fcd25166SAndrew Lunn { 8033b19df73SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6352_G2_WDOG_CTL, 8043b19df73SVivien Didelot MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE | 8053b19df73SVivien Didelot MV88E6352_G2_WDOG_CTL_QC_ENABLE | 8063b19df73SVivien Didelot MV88E6352_G2_WDOG_CTL_SWRESET); 807fcd25166SAndrew Lunn } 808fcd25166SAndrew Lunn 809fcd25166SAndrew Lunn const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = { 810fcd25166SAndrew Lunn .irq_action = mv88e6097_watchdog_action, 811fcd25166SAndrew Lunn .irq_setup = mv88e6097_watchdog_setup, 812fcd25166SAndrew Lunn .irq_free = mv88e6097_watchdog_free, 813fcd25166SAndrew Lunn }; 814fcd25166SAndrew Lunn 81561303736SAndrew Lunn static int mv88e6390_watchdog_setup(struct mv88e6xxx_chip *chip) 81661303736SAndrew Lunn { 8173b19df73SVivien Didelot return mv88e6xxx_g2_update(chip, MV88E6390_G2_WDOG_CTL, 8183b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE | 8193b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_CUT_THROUGH | 8203b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_QUEUE_CONTROLLER | 8213b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_EGRESS | 8223b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_FORCE_IRQ); 82361303736SAndrew Lunn } 82461303736SAndrew Lunn 82561303736SAndrew Lunn static int mv88e6390_watchdog_action(struct mv88e6xxx_chip *chip, int irq) 82661303736SAndrew Lunn { 82761303736SAndrew Lunn int err; 82861303736SAndrew Lunn u16 reg; 82961303736SAndrew Lunn 8303b19df73SVivien Didelot mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL, 8313b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_PTR_EVENT); 8323b19df73SVivien Didelot err = mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, ®); 83361303736SAndrew Lunn 83461303736SAndrew Lunn dev_info(chip->dev, "Watchdog event: 0x%04x", 8353b19df73SVivien Didelot reg & MV88E6390_G2_WDOG_CTL_DATA_MASK); 83661303736SAndrew Lunn 8373b19df73SVivien Didelot mv88e6xxx_g2_write(chip, MV88E6390_G2_WDOG_CTL, 8383b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_PTR_HISTORY); 8393b19df73SVivien Didelot err = mv88e6xxx_g2_read(chip, MV88E6390_G2_WDOG_CTL, ®); 84061303736SAndrew Lunn 84161303736SAndrew Lunn dev_info(chip->dev, "Watchdog history: 0x%04x", 8423b19df73SVivien Didelot reg & MV88E6390_G2_WDOG_CTL_DATA_MASK); 84361303736SAndrew Lunn 84461303736SAndrew Lunn /* Trigger a software reset to try to recover the switch */ 84561303736SAndrew Lunn if (chip->info->ops->reset) 84661303736SAndrew Lunn chip->info->ops->reset(chip); 84761303736SAndrew Lunn 84861303736SAndrew Lunn mv88e6390_watchdog_setup(chip); 84961303736SAndrew Lunn 85061303736SAndrew Lunn return IRQ_HANDLED; 85161303736SAndrew Lunn } 85261303736SAndrew Lunn 85361303736SAndrew Lunn static void mv88e6390_watchdog_free(struct mv88e6xxx_chip *chip) 85461303736SAndrew Lunn { 8553b19df73SVivien Didelot mv88e6xxx_g2_update(chip, MV88E6390_G2_WDOG_CTL, 8563b19df73SVivien Didelot MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE); 85761303736SAndrew Lunn } 85861303736SAndrew Lunn 85961303736SAndrew Lunn const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = { 86061303736SAndrew Lunn .irq_action = mv88e6390_watchdog_action, 86161303736SAndrew Lunn .irq_setup = mv88e6390_watchdog_setup, 86261303736SAndrew Lunn .irq_free = mv88e6390_watchdog_free, 86361303736SAndrew Lunn }; 86461303736SAndrew Lunn 865fcd25166SAndrew Lunn static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id) 866fcd25166SAndrew Lunn { 867fcd25166SAndrew Lunn struct mv88e6xxx_chip *chip = dev_id; 868fcd25166SAndrew Lunn irqreturn_t ret = IRQ_NONE; 869fcd25166SAndrew Lunn 870fcd25166SAndrew Lunn mutex_lock(&chip->reg_lock); 871fcd25166SAndrew Lunn if (chip->info->ops->watchdog_ops->irq_action) 872fcd25166SAndrew Lunn ret = chip->info->ops->watchdog_ops->irq_action(chip, irq); 873fcd25166SAndrew Lunn mutex_unlock(&chip->reg_lock); 874fcd25166SAndrew Lunn 875fcd25166SAndrew Lunn return ret; 876fcd25166SAndrew Lunn } 877fcd25166SAndrew Lunn 878fcd25166SAndrew Lunn static void mv88e6xxx_g2_watchdog_free(struct mv88e6xxx_chip *chip) 879fcd25166SAndrew Lunn { 880fcd25166SAndrew Lunn mutex_lock(&chip->reg_lock); 881fcd25166SAndrew Lunn if (chip->info->ops->watchdog_ops->irq_free) 882fcd25166SAndrew Lunn chip->info->ops->watchdog_ops->irq_free(chip); 883fcd25166SAndrew Lunn mutex_unlock(&chip->reg_lock); 884fcd25166SAndrew Lunn 885fcd25166SAndrew Lunn free_irq(chip->watchdog_irq, chip); 886fcd25166SAndrew Lunn irq_dispose_mapping(chip->watchdog_irq); 887fcd25166SAndrew Lunn } 888fcd25166SAndrew Lunn 889fcd25166SAndrew Lunn static int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip) 890fcd25166SAndrew Lunn { 891fcd25166SAndrew Lunn int err; 892fcd25166SAndrew Lunn 893fcd25166SAndrew Lunn chip->watchdog_irq = irq_find_mapping(chip->g2_irq.domain, 8941d90016dSVivien Didelot MV88E6XXX_G2_INT_SOURCE_WATCHDOG); 895fcd25166SAndrew Lunn if (chip->watchdog_irq < 0) 896fcd25166SAndrew Lunn return chip->watchdog_irq; 897fcd25166SAndrew Lunn 898fcd25166SAndrew Lunn err = request_threaded_irq(chip->watchdog_irq, NULL, 899fcd25166SAndrew Lunn mv88e6xxx_g2_watchdog_thread_fn, 900fcd25166SAndrew Lunn IRQF_ONESHOT | IRQF_TRIGGER_FALLING, 901fcd25166SAndrew Lunn "mv88e6xxx-watchdog", chip); 902fcd25166SAndrew Lunn if (err) 903fcd25166SAndrew Lunn return err; 904fcd25166SAndrew Lunn 905fcd25166SAndrew Lunn mutex_lock(&chip->reg_lock); 906fcd25166SAndrew Lunn if (chip->info->ops->watchdog_ops->irq_setup) 907fcd25166SAndrew Lunn err = chip->info->ops->watchdog_ops->irq_setup(chip); 908fcd25166SAndrew Lunn mutex_unlock(&chip->reg_lock); 909fcd25166SAndrew Lunn 910fcd25166SAndrew Lunn return err; 911fcd25166SAndrew Lunn } 912fcd25166SAndrew Lunn 91381228996SVivien Didelot /* Offset 0x1D: Misc Register */ 91481228996SVivien Didelot 91581228996SVivien Didelot static int mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip *chip, 91681228996SVivien Didelot bool port_5_bit) 91781228996SVivien Didelot { 91881228996SVivien Didelot u16 val; 91981228996SVivien Didelot int err; 92081228996SVivien Didelot 9211d90016dSVivien Didelot err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_MISC, &val); 92281228996SVivien Didelot if (err) 92381228996SVivien Didelot return err; 92481228996SVivien Didelot 92581228996SVivien Didelot if (port_5_bit) 9261d90016dSVivien Didelot val |= MV88E6XXX_G2_MISC_5_BIT_PORT; 92781228996SVivien Didelot else 9281d90016dSVivien Didelot val &= ~MV88E6XXX_G2_MISC_5_BIT_PORT; 92981228996SVivien Didelot 9301d90016dSVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MISC, val); 93181228996SVivien Didelot } 93281228996SVivien Didelot 93381228996SVivien Didelot int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip) 93481228996SVivien Didelot { 93581228996SVivien Didelot return mv88e6xxx_g2_misc_5_bit_port(chip, false); 93681228996SVivien Didelot } 93781228996SVivien Didelot 938dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_mask(struct irq_data *d) 939dc30c35bSAndrew Lunn { 940dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 941dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 942dc30c35bSAndrew Lunn 943dc30c35bSAndrew Lunn chip->g2_irq.masked |= (1 << n); 944dc30c35bSAndrew Lunn } 945dc30c35bSAndrew Lunn 946dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_unmask(struct irq_data *d) 947dc30c35bSAndrew Lunn { 948dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 949dc30c35bSAndrew Lunn unsigned int n = d->hwirq; 950dc30c35bSAndrew Lunn 951dc30c35bSAndrew Lunn chip->g2_irq.masked &= ~(1 << n); 952dc30c35bSAndrew Lunn } 953dc30c35bSAndrew Lunn 954dc30c35bSAndrew Lunn static irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id) 955dc30c35bSAndrew Lunn { 956dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = dev_id; 957dc30c35bSAndrew Lunn unsigned int nhandled = 0; 958dc30c35bSAndrew Lunn unsigned int sub_irq; 959dc30c35bSAndrew Lunn unsigned int n; 960dc30c35bSAndrew Lunn int err; 961dc30c35bSAndrew Lunn u16 reg; 962dc30c35bSAndrew Lunn 963dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 964d6c5e6afSVivien Didelot err = mv88e6xxx_g2_int_source(chip, ®); 965dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 966dc30c35bSAndrew Lunn if (err) 967dc30c35bSAndrew Lunn goto out; 968dc30c35bSAndrew Lunn 969dc30c35bSAndrew Lunn for (n = 0; n < 16; ++n) { 970dc30c35bSAndrew Lunn if (reg & (1 << n)) { 971dc30c35bSAndrew Lunn sub_irq = irq_find_mapping(chip->g2_irq.domain, n); 972dc30c35bSAndrew Lunn handle_nested_irq(sub_irq); 973dc30c35bSAndrew Lunn ++nhandled; 974dc30c35bSAndrew Lunn } 975dc30c35bSAndrew Lunn } 976dc30c35bSAndrew Lunn out: 977dc30c35bSAndrew Lunn return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); 978dc30c35bSAndrew Lunn } 979dc30c35bSAndrew Lunn 980dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_bus_lock(struct irq_data *d) 981dc30c35bSAndrew Lunn { 982dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 983dc30c35bSAndrew Lunn 984dc30c35bSAndrew Lunn mutex_lock(&chip->reg_lock); 985dc30c35bSAndrew Lunn } 986dc30c35bSAndrew Lunn 987dc30c35bSAndrew Lunn static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d) 988dc30c35bSAndrew Lunn { 989dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); 990d6c5e6afSVivien Didelot int err; 991dc30c35bSAndrew Lunn 992d6c5e6afSVivien Didelot err = mv88e6xxx_g2_int_mask(chip, ~chip->g2_irq.masked); 993d6c5e6afSVivien Didelot if (err) 994d6c5e6afSVivien Didelot dev_err(chip->dev, "failed to mask interrupts\n"); 995dc30c35bSAndrew Lunn 996dc30c35bSAndrew Lunn mutex_unlock(&chip->reg_lock); 997dc30c35bSAndrew Lunn } 998dc30c35bSAndrew Lunn 9996eb15e21SBhumika Goyal static const struct irq_chip mv88e6xxx_g2_irq_chip = { 1000dc30c35bSAndrew Lunn .name = "mv88e6xxx-g2", 1001dc30c35bSAndrew Lunn .irq_mask = mv88e6xxx_g2_irq_mask, 1002dc30c35bSAndrew Lunn .irq_unmask = mv88e6xxx_g2_irq_unmask, 1003dc30c35bSAndrew Lunn .irq_bus_lock = mv88e6xxx_g2_irq_bus_lock, 1004dc30c35bSAndrew Lunn .irq_bus_sync_unlock = mv88e6xxx_g2_irq_bus_sync_unlock, 1005dc30c35bSAndrew Lunn }; 1006dc30c35bSAndrew Lunn 1007dc30c35bSAndrew Lunn static int mv88e6xxx_g2_irq_domain_map(struct irq_domain *d, 1008dc30c35bSAndrew Lunn unsigned int irq, 1009dc30c35bSAndrew Lunn irq_hw_number_t hwirq) 1010dc30c35bSAndrew Lunn { 1011dc30c35bSAndrew Lunn struct mv88e6xxx_chip *chip = d->host_data; 1012dc30c35bSAndrew Lunn 1013dc30c35bSAndrew Lunn irq_set_chip_data(irq, d->host_data); 1014dc30c35bSAndrew Lunn irq_set_chip_and_handler(irq, &chip->g2_irq.chip, handle_level_irq); 1015dc30c35bSAndrew Lunn irq_set_noprobe(irq); 1016dc30c35bSAndrew Lunn 1017dc30c35bSAndrew Lunn return 0; 1018dc30c35bSAndrew Lunn } 1019dc30c35bSAndrew Lunn 1020dc30c35bSAndrew Lunn static const struct irq_domain_ops mv88e6xxx_g2_irq_domain_ops = { 1021dc30c35bSAndrew Lunn .map = mv88e6xxx_g2_irq_domain_map, 1022dc30c35bSAndrew Lunn .xlate = irq_domain_xlate_twocell, 1023dc30c35bSAndrew Lunn }; 1024dc30c35bSAndrew Lunn 1025dc30c35bSAndrew Lunn void mv88e6xxx_g2_irq_free(struct mv88e6xxx_chip *chip) 1026dc30c35bSAndrew Lunn { 1027dc30c35bSAndrew Lunn int irq, virq; 1028dc30c35bSAndrew Lunn 1029fcd25166SAndrew Lunn mv88e6xxx_g2_watchdog_free(chip); 1030fcd25166SAndrew Lunn 10318e757ebaSAndrew Lunn free_irq(chip->device_irq, chip); 10328e757ebaSAndrew Lunn irq_dispose_mapping(chip->device_irq); 10338e757ebaSAndrew Lunn 1034dc30c35bSAndrew Lunn for (irq = 0; irq < 16; irq++) { 1035dc30c35bSAndrew Lunn virq = irq_find_mapping(chip->g2_irq.domain, irq); 1036dc30c35bSAndrew Lunn irq_dispose_mapping(virq); 1037dc30c35bSAndrew Lunn } 1038dc30c35bSAndrew Lunn 1039dc30c35bSAndrew Lunn irq_domain_remove(chip->g2_irq.domain); 1040dc30c35bSAndrew Lunn } 1041dc30c35bSAndrew Lunn 1042dc30c35bSAndrew Lunn int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip) 1043dc30c35bSAndrew Lunn { 10448e757ebaSAndrew Lunn int err, irq, virq; 1045dc30c35bSAndrew Lunn 1046dc30c35bSAndrew Lunn chip->g2_irq.domain = irq_domain_add_simple( 1047dc30c35bSAndrew Lunn chip->dev->of_node, 16, 0, &mv88e6xxx_g2_irq_domain_ops, chip); 1048dc30c35bSAndrew Lunn if (!chip->g2_irq.domain) 1049dc30c35bSAndrew Lunn return -ENOMEM; 1050dc30c35bSAndrew Lunn 1051dc30c35bSAndrew Lunn for (irq = 0; irq < 16; irq++) 1052dc30c35bSAndrew Lunn irq_create_mapping(chip->g2_irq.domain, irq); 1053dc30c35bSAndrew Lunn 1054dc30c35bSAndrew Lunn chip->g2_irq.chip = mv88e6xxx_g2_irq_chip; 1055dc30c35bSAndrew Lunn chip->g2_irq.masked = ~0; 1056dc30c35bSAndrew Lunn 10578e757ebaSAndrew Lunn chip->device_irq = irq_find_mapping(chip->g1_irq.domain, 105882466921SVivien Didelot MV88E6XXX_G1_STS_IRQ_DEVICE); 10598e757ebaSAndrew Lunn if (chip->device_irq < 0) { 10608e757ebaSAndrew Lunn err = chip->device_irq; 1061dc30c35bSAndrew Lunn goto out; 1062dc30c35bSAndrew Lunn } 1063dc30c35bSAndrew Lunn 10648e757ebaSAndrew Lunn err = request_threaded_irq(chip->device_irq, NULL, 1065dc30c35bSAndrew Lunn mv88e6xxx_g2_irq_thread_fn, 106636d6ea94SUwe Kleine-König IRQF_ONESHOT, "mv88e6xxx-g2", chip); 1067dc30c35bSAndrew Lunn if (err) 1068dc30c35bSAndrew Lunn goto out; 1069dc30c35bSAndrew Lunn 1070fcd25166SAndrew Lunn return mv88e6xxx_g2_watchdog_setup(chip); 10718e757ebaSAndrew Lunn 1072dc30c35bSAndrew Lunn out: 10738e757ebaSAndrew Lunn for (irq = 0; irq < 16; irq++) { 10748e757ebaSAndrew Lunn virq = irq_find_mapping(chip->g2_irq.domain, irq); 10758e757ebaSAndrew Lunn irq_dispose_mapping(virq); 10768e757ebaSAndrew Lunn } 10778e757ebaSAndrew Lunn 10788e757ebaSAndrew Lunn irq_domain_remove(chip->g2_irq.domain); 1079dc30c35bSAndrew Lunn 1080dc30c35bSAndrew Lunn return err; 1081dc30c35bSAndrew Lunn } 1082dc30c35bSAndrew Lunn 10836f88284fSAndrew Lunn int mv88e6xxx_g2_irq_mdio_setup(struct mv88e6xxx_chip *chip, 10846f88284fSAndrew Lunn struct mii_bus *bus) 10856f88284fSAndrew Lunn { 10866f88284fSAndrew Lunn int phy, irq, err, err_phy; 10876f88284fSAndrew Lunn 10886f88284fSAndrew Lunn for (phy = 0; phy < chip->info->num_internal_phys; phy++) { 10896f88284fSAndrew Lunn irq = irq_find_mapping(chip->g2_irq.domain, phy); 10906f88284fSAndrew Lunn if (irq < 0) { 10916f88284fSAndrew Lunn err = irq; 10926f88284fSAndrew Lunn goto out; 10936f88284fSAndrew Lunn } 10949255bacdSAndrew Lunn bus->irq[chip->info->phy_base_addr + phy] = irq; 10956f88284fSAndrew Lunn } 10966f88284fSAndrew Lunn return 0; 10976f88284fSAndrew Lunn out: 10986f88284fSAndrew Lunn err_phy = phy; 10996f88284fSAndrew Lunn 11006f88284fSAndrew Lunn for (phy = 0; phy < err_phy; phy++) 11016f88284fSAndrew Lunn irq_dispose_mapping(bus->irq[phy]); 11026f88284fSAndrew Lunn 11036f88284fSAndrew Lunn return err; 11046f88284fSAndrew Lunn } 11056f88284fSAndrew Lunn 11066f88284fSAndrew Lunn void mv88e6xxx_g2_irq_mdio_free(struct mv88e6xxx_chip *chip, 11076f88284fSAndrew Lunn struct mii_bus *bus) 11086f88284fSAndrew Lunn { 11096f88284fSAndrew Lunn int phy; 11106f88284fSAndrew Lunn 11116f88284fSAndrew Lunn for (phy = 0; phy < chip->info->num_internal_phys; phy++) 11126f88284fSAndrew Lunn irq_dispose_mapping(bus->irq[phy]); 11136f88284fSAndrew Lunn } 1114