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