// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88E6xxx Switch Global 2 Registers support
*
* Copyright (c) 2008 Marvell Semiconductor
*
* Copyright (c) 2016-2017 Savoir-faire Linux Inc.
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
*/
#include <linux/bitfield.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include "chip.h"
#include "global1.h" /* for MV88E6XXX_G1_STS_IRQ_DEVICE */
#include "global2.h"
int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
{
return mv88e6xxx_read(chip, chip->info->global2_addr, reg, val);
}
int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
{
return mv88e6xxx_write(chip, chip->info->global2_addr, reg, val);
}
int mv88e6xxx_g2_wait_bit(struct mv88e6xxx_chip *chip, int reg, int
bit, int val)
{
return mv88e6xxx_wait_bit(chip, chip->info->global2_addr, reg,
bit, val);
}
/* Offset 0x00: Interrupt Source Register */
static int mv88e6xxx_g2_int_source(struct mv88e6xxx_chip *chip, u16 *src)
{
/* Read (and clear most of) the Interrupt Source bits */
return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_INT_SRC, src);
}
/* Offset 0x01: Interrupt Mask Register */
static int mv88e6xxx_g2_int_mask(struct mv88e6xxx_chip *chip, u16 mask)
{
return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_INT_MASK, mask);
}
/* Offset 0x02: Management Enable 2x */
static int mv88e6xxx_g2_mgmt_enable_2x(struct mv88e6xxx_chip *chip, u16 en2x)
{
return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_2X, en2x);
}
/* Offset 0x03: Management Enable 0x */
static int mv88e6xxx_g2_mgmt_enable_0x(struct mv88e6xxx_chip *chip, u16 en0x)
{
return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_MGMT_EN_0X, en0x);
}
/* Offset 0x05: Switch Management Register */
static int mv88e6xxx_g2_switch_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip,
bool enable)
{
u16 val;
int err;
err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SWITCH_MGMT, &val);
if (err)
return err;
if (enable)
val |= MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU;
else
val &= ~MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU;
return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SWITCH_MGMT, val);
}
int mv88e6185_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
{
int err;
/* Consider the frames with reserved multicast destination
* addresses matching 01:80:c2:00:00:0x as MGMT.
*/
err = mv88e6xxx_g2_mgmt_enable_0x(chip, 0xffff);
if (err)
return err;
return mv88e6xxx_g2_switch_mgmt_rsvd2cpu(chip, true);
}
int mv88e6352_g2_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
{
int err;
/* Consider the frames with reserved multicast destination
* addresses matching 01:80:c2:00:00:2x as MGMT.
*/
err = mv88e6xxx_g2_mgmt_enable_2x(chip, 0xffff);
if (err)
return err;
return mv88e6185_g2_mgmt_rsvd2cpu(chip);
}
/* Offset 0x06: Device Mapping Table register */
int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target,
int port)
{
u16 val = (target << 8) | (port & 0x1f);
/* Modern chips use 5 bits to define a device mapping port,
* but bit 4 is reserved on older chips, so it is safe to use.
*/
return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_DEVICE_MAPPING,
MV88E6XXX_G2_DEVICE_MAPPING_UPDATE | val);