diff options
Diffstat (limited to 'drivers/net/dsa/mv88e6xxx/global2.c')
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/global2.c | 101 |
1 files changed, 84 insertions, 17 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index 8f15bc7b1f5f..b3fea55071e3 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -4,7 +4,8 @@ * * Copyright (c) 2008 Marvell Semiconductor * - * Copyright (c) 2016 Vivien Didelot <vivien.didelot@savoirfairelinux.com> + * Copyright (c) 2016-2017 Savoir-faire Linux Inc. + * Vivien Didelot <vivien.didelot@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -12,6 +13,7 @@ * (at your option) any later version. */ +#include <linux/interrupt.h> #include <linux/irqdomain.h> #include "mv88e6xxx.h" #include "global2.h" @@ -170,6 +172,50 @@ static int mv88e6xxx_g2_clear_irl(struct mv88e6xxx_chip *chip) return err; } +/* Offset 0x0B: Cross-chip Port VLAN (Addr) Register + * Offset 0x0C: Cross-chip Port VLAN Data Register + */ + +static int mv88e6xxx_g2_pvt_op_wait(struct mv88e6xxx_chip *chip) +{ + return mv88e6xxx_g2_wait(chip, GLOBAL2_PVT_ADDR, GLOBAL2_PVT_ADDR_BUSY); +} + +static int mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip *chip, int src_dev, + int src_port, u16 op) +{ + int err; + + /* 9-bit Cross-chip PVT pointer: with GLOBAL2_MISC_5_BIT_PORT cleared, + * source device is 5-bit, source port is 4-bit. + */ + op |= (src_dev & 0x1f) << 4; + op |= (src_port & 0xf); + + err = mv88e6xxx_g2_write(chip, GLOBAL2_PVT_ADDR, op); + if (err) + return err; + + return mv88e6xxx_g2_pvt_op_wait(chip); +} + +int mv88e6xxx_g2_pvt_write(struct mv88e6xxx_chip *chip, int src_dev, + int src_port, u16 data) +{ + int err; + + err = mv88e6xxx_g2_pvt_op_wait(chip); + if (err) + return err; + + err = mv88e6xxx_g2_write(chip, GLOBAL2_PVT_DATA, data); + if (err) + return err; + + return mv88e6xxx_g2_pvt_op(chip, src_dev, src_port, + GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN); +} + /* Offset 0x0D: Switch MAC/WoL/WoF register */ static int mv88e6xxx_g2_switch_mac_write(struct mv88e6xxx_chip *chip, @@ -522,8 +568,9 @@ static int mv88e6xxx_g2_smi_phy_write_addr(struct mv88e6xxx_chip *chip, return mv88e6xxx_g2_smi_phy_cmd(chip, cmd); } -int mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip, int addr, - int reg_c45, u16 *val, bool external) +static int mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip, + int addr, int reg_c45, u16 *val, + bool external) { int device = (reg_c45 >> 16) & 0x1f; int reg = reg_c45 & 0xffff; @@ -553,8 +600,9 @@ int mv88e6xxx_g2_smi_phy_read_c45(struct mv88e6xxx_chip *chip, int addr, return 0; } -int mv88e6xxx_g2_smi_phy_read_c22(struct mv88e6xxx_chip *chip, int addr, - int reg, u16 *val, bool external) +static int mv88e6xxx_g2_smi_phy_read_c22(struct mv88e6xxx_chip *chip, + int addr, int reg, u16 *val, + bool external) { u16 cmd = GLOBAL2_SMI_PHY_CMD_OP_22_READ_DATA | (addr << 5) | reg; int err; @@ -586,8 +634,9 @@ int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, return mv88e6xxx_g2_smi_phy_read_c22(chip, addr, reg, val, external); } -int mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip, int addr, - int reg_c45, u16 val, bool external) +static int mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip, + int addr, int reg_c45, u16 val, + bool external) { int device = (reg_c45 >> 16) & 0x1f; int reg = reg_c45 & 0xffff; @@ -615,8 +664,9 @@ int mv88e6xxx_g2_smi_phy_write_c45(struct mv88e6xxx_chip *chip, int addr, return 0; } -int mv88e6xxx_g2_smi_phy_write_c22(struct mv88e6xxx_chip *chip, int addr, - int reg, u16 val, bool external) +static int mv88e6xxx_g2_smi_phy_write_c22(struct mv88e6xxx_chip *chip, + int addr, int reg, u16 val, + bool external) { u16 cmd = GLOBAL2_SMI_PHY_CMD_OP_22_WRITE_DATA | (addr << 5) | reg; int err; @@ -782,6 +832,31 @@ static int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip) return err; } +/* Offset 0x1D: Misc Register */ + +static int mv88e6xxx_g2_misc_5_bit_port(struct mv88e6xxx_chip *chip, + bool port_5_bit) +{ + u16 val; + int err; + + err = mv88e6xxx_g2_read(chip, GLOBAL2_MISC, &val); + if (err) + return err; + + if (port_5_bit) + val |= GLOBAL2_MISC_5_BIT_PORT; + else + val &= ~GLOBAL2_MISC_5_BIT_PORT; + + return mv88e6xxx_g2_write(chip, GLOBAL2_MISC, val); +} + +int mv88e6xxx_g2_misc_4_bit_port(struct mv88e6xxx_chip *chip) +{ + return mv88e6xxx_g2_misc_5_bit_port(chip, false); +} + static void mv88e6xxx_g2_irq_mask(struct irq_data *d) { struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d); @@ -964,14 +1039,6 @@ int mv88e6xxx_g2_setup(struct mv88e6xxx_chip *chip) return err; } - if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_PVT)) { - /* Initialize Cross-chip Port VLAN Table to reset defaults */ - err = mv88e6xxx_g2_write(chip, GLOBAL2_PVT_ADDR, - GLOBAL2_PVT_ADDR_OP_INIT_ONES); - if (err) - return err; - } - if (mv88e6xxx_has(chip, MV88E6XXX_FLAG_G2_POT)) { /* Clear the priority override table. */ err = mv88e6xxx_g2_clear_pot(chip); |