118abed21SVivien Didelot /* 218abed21SVivien Didelot * Marvell 88E6xxx Switch Port Registers support 318abed21SVivien Didelot * 418abed21SVivien Didelot * Copyright (c) 2008 Marvell Semiconductor 518abed21SVivien Didelot * 64333d619SVivien Didelot * Copyright (c) 2016-2017 Savoir-faire Linux Inc. 74333d619SVivien Didelot * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 818abed21SVivien Didelot * 918abed21SVivien Didelot * This program is free software; you can redistribute it and/or modify 1018abed21SVivien Didelot * it under the terms of the GNU General Public License as published by 1118abed21SVivien Didelot * the Free Software Foundation; either version 2 of the License, or 1218abed21SVivien Didelot * (at your option) any later version. 1318abed21SVivien Didelot */ 1418abed21SVivien Didelot 15f39908d3SAndrew Lunn #include <linux/phy.h> 16*4d5f2ba7SVivien Didelot 17*4d5f2ba7SVivien Didelot #include "chip.h" 1818abed21SVivien Didelot #include "port.h" 1918abed21SVivien Didelot 2018abed21SVivien Didelot int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg, 2118abed21SVivien Didelot u16 *val) 2218abed21SVivien Didelot { 2318abed21SVivien Didelot int addr = chip->info->port_base_addr + port; 2418abed21SVivien Didelot 2518abed21SVivien Didelot return mv88e6xxx_read(chip, addr, reg, val); 2618abed21SVivien Didelot } 2718abed21SVivien Didelot 2818abed21SVivien Didelot int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg, 2918abed21SVivien Didelot u16 val) 3018abed21SVivien Didelot { 3118abed21SVivien Didelot int addr = chip->info->port_base_addr + port; 3218abed21SVivien Didelot 3318abed21SVivien Didelot return mv88e6xxx_write(chip, addr, reg, val); 3418abed21SVivien Didelot } 35e28def33SVivien Didelot 3608ef7f10SVivien Didelot /* Offset 0x01: MAC (or PCS or Physical) Control Register 3708ef7f10SVivien Didelot * 3808ef7f10SVivien Didelot * Link, Duplex and Flow Control have one force bit, one value bit. 3996a2b40cSVivien Didelot * 4096a2b40cSVivien Didelot * For port's MAC speed, ForceSpd (or SpdValue) bits 1:0 program the value. 4196a2b40cSVivien Didelot * Alternative values require the 200BASE (or AltSpeed) bit 12 set. 4296a2b40cSVivien Didelot * Newer chips need a ForcedSpd bit 13 set to consider the value. 4308ef7f10SVivien Didelot */ 4408ef7f10SVivien Didelot 45a0a0f622SVivien Didelot static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, 46a0a0f622SVivien Didelot phy_interface_t mode) 47a0a0f622SVivien Didelot { 48a0a0f622SVivien Didelot u16 reg; 49a0a0f622SVivien Didelot int err; 50a0a0f622SVivien Didelot 51a0a0f622SVivien Didelot err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, ®); 52a0a0f622SVivien Didelot if (err) 53a0a0f622SVivien Didelot return err; 54a0a0f622SVivien Didelot 55a0a0f622SVivien Didelot reg &= ~(PORT_PCS_CTRL_RGMII_DELAY_RXCLK | 56a0a0f622SVivien Didelot PORT_PCS_CTRL_RGMII_DELAY_TXCLK); 57a0a0f622SVivien Didelot 58a0a0f622SVivien Didelot switch (mode) { 59a0a0f622SVivien Didelot case PHY_INTERFACE_MODE_RGMII_RXID: 60a0a0f622SVivien Didelot reg |= PORT_PCS_CTRL_RGMII_DELAY_RXCLK; 61a0a0f622SVivien Didelot break; 62a0a0f622SVivien Didelot case PHY_INTERFACE_MODE_RGMII_TXID: 63a0a0f622SVivien Didelot reg |= PORT_PCS_CTRL_RGMII_DELAY_TXCLK; 64a0a0f622SVivien Didelot break; 65a0a0f622SVivien Didelot case PHY_INTERFACE_MODE_RGMII_ID: 66a0a0f622SVivien Didelot reg |= PORT_PCS_CTRL_RGMII_DELAY_RXCLK | 67a0a0f622SVivien Didelot PORT_PCS_CTRL_RGMII_DELAY_TXCLK; 68a0a0f622SVivien Didelot break; 69fedf1865SAndrew Lunn case PHY_INTERFACE_MODE_RGMII: 70a0a0f622SVivien Didelot break; 71fedf1865SAndrew Lunn default: 72fedf1865SAndrew Lunn return 0; 73a0a0f622SVivien Didelot } 74a0a0f622SVivien Didelot 75a0a0f622SVivien Didelot err = mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg); 76a0a0f622SVivien Didelot if (err) 77a0a0f622SVivien Didelot return err; 78a0a0f622SVivien Didelot 79a0a0f622SVivien Didelot netdev_dbg(chip->ds->ports[port].netdev, "delay RXCLK %s, TXCLK %s\n", 80a0a0f622SVivien Didelot reg & PORT_PCS_CTRL_RGMII_DELAY_RXCLK ? "yes" : "no", 81a0a0f622SVivien Didelot reg & PORT_PCS_CTRL_RGMII_DELAY_TXCLK ? "yes" : "no"); 82a0a0f622SVivien Didelot 83a0a0f622SVivien Didelot return 0; 84a0a0f622SVivien Didelot } 85a0a0f622SVivien Didelot 86a0a0f622SVivien Didelot int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, 87a0a0f622SVivien Didelot phy_interface_t mode) 88a0a0f622SVivien Didelot { 89a0a0f622SVivien Didelot if (port < 5) 90a0a0f622SVivien Didelot return -EOPNOTSUPP; 91a0a0f622SVivien Didelot 92a0a0f622SVivien Didelot return mv88e6xxx_port_set_rgmii_delay(chip, port, mode); 93a0a0f622SVivien Didelot } 94a0a0f622SVivien Didelot 95a0a0f622SVivien Didelot int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, 96a0a0f622SVivien Didelot phy_interface_t mode) 97a0a0f622SVivien Didelot { 98a0a0f622SVivien Didelot if (port != 0) 99a0a0f622SVivien Didelot return -EOPNOTSUPP; 100a0a0f622SVivien Didelot 101a0a0f622SVivien Didelot return mv88e6xxx_port_set_rgmii_delay(chip, port, mode); 102a0a0f622SVivien Didelot } 103a0a0f622SVivien Didelot 10408ef7f10SVivien Didelot int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link) 10508ef7f10SVivien Didelot { 10608ef7f10SVivien Didelot u16 reg; 10708ef7f10SVivien Didelot int err; 10808ef7f10SVivien Didelot 10908ef7f10SVivien Didelot err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, ®); 11008ef7f10SVivien Didelot if (err) 11108ef7f10SVivien Didelot return err; 11208ef7f10SVivien Didelot 11308ef7f10SVivien Didelot reg &= ~(PORT_PCS_CTRL_FORCE_LINK | PORT_PCS_CTRL_LINK_UP); 11408ef7f10SVivien Didelot 11508ef7f10SVivien Didelot switch (link) { 11608ef7f10SVivien Didelot case LINK_FORCED_DOWN: 11708ef7f10SVivien Didelot reg |= PORT_PCS_CTRL_FORCE_LINK; 11808ef7f10SVivien Didelot break; 11908ef7f10SVivien Didelot case LINK_FORCED_UP: 12008ef7f10SVivien Didelot reg |= PORT_PCS_CTRL_FORCE_LINK | PORT_PCS_CTRL_LINK_UP; 12108ef7f10SVivien Didelot break; 12208ef7f10SVivien Didelot case LINK_UNFORCED: 12308ef7f10SVivien Didelot /* normal link detection */ 12408ef7f10SVivien Didelot break; 12508ef7f10SVivien Didelot default: 12608ef7f10SVivien Didelot return -EINVAL; 12708ef7f10SVivien Didelot } 12808ef7f10SVivien Didelot 12908ef7f10SVivien Didelot err = mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg); 13008ef7f10SVivien Didelot if (err) 13108ef7f10SVivien Didelot return err; 13208ef7f10SVivien Didelot 13308ef7f10SVivien Didelot netdev_dbg(chip->ds->ports[port].netdev, "%s link %s\n", 13408ef7f10SVivien Didelot reg & PORT_PCS_CTRL_FORCE_LINK ? "Force" : "Unforce", 13508ef7f10SVivien Didelot reg & PORT_PCS_CTRL_LINK_UP ? "up" : "down"); 13608ef7f10SVivien Didelot 13708ef7f10SVivien Didelot return 0; 13808ef7f10SVivien Didelot } 13908ef7f10SVivien Didelot 1407f1ae07bSVivien Didelot int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup) 1417f1ae07bSVivien Didelot { 1427f1ae07bSVivien Didelot u16 reg; 1437f1ae07bSVivien Didelot int err; 1447f1ae07bSVivien Didelot 1457f1ae07bSVivien Didelot err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, ®); 1467f1ae07bSVivien Didelot if (err) 1477f1ae07bSVivien Didelot return err; 1487f1ae07bSVivien Didelot 1497f1ae07bSVivien Didelot reg &= ~(PORT_PCS_CTRL_FORCE_DUPLEX | PORT_PCS_CTRL_DUPLEX_FULL); 1507f1ae07bSVivien Didelot 1517f1ae07bSVivien Didelot switch (dup) { 1527f1ae07bSVivien Didelot case DUPLEX_HALF: 1537f1ae07bSVivien Didelot reg |= PORT_PCS_CTRL_FORCE_DUPLEX; 1547f1ae07bSVivien Didelot break; 1557f1ae07bSVivien Didelot case DUPLEX_FULL: 1567f1ae07bSVivien Didelot reg |= PORT_PCS_CTRL_FORCE_DUPLEX | PORT_PCS_CTRL_DUPLEX_FULL; 1577f1ae07bSVivien Didelot break; 1587f1ae07bSVivien Didelot case DUPLEX_UNFORCED: 1597f1ae07bSVivien Didelot /* normal duplex detection */ 1607f1ae07bSVivien Didelot break; 1617f1ae07bSVivien Didelot default: 1627f1ae07bSVivien Didelot return -EINVAL; 1637f1ae07bSVivien Didelot } 1647f1ae07bSVivien Didelot 1657f1ae07bSVivien Didelot err = mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg); 1667f1ae07bSVivien Didelot if (err) 1677f1ae07bSVivien Didelot return err; 1687f1ae07bSVivien Didelot 1697f1ae07bSVivien Didelot netdev_dbg(chip->ds->ports[port].netdev, "%s %s duplex\n", 1707f1ae07bSVivien Didelot reg & PORT_PCS_CTRL_FORCE_DUPLEX ? "Force" : "Unforce", 1717f1ae07bSVivien Didelot reg & PORT_PCS_CTRL_DUPLEX_FULL ? "full" : "half"); 1727f1ae07bSVivien Didelot 1737f1ae07bSVivien Didelot return 0; 1747f1ae07bSVivien Didelot } 1757f1ae07bSVivien Didelot 17696a2b40cSVivien Didelot static int mv88e6xxx_port_set_speed(struct mv88e6xxx_chip *chip, int port, 17796a2b40cSVivien Didelot int speed, bool alt_bit, bool force_bit) 17896a2b40cSVivien Didelot { 17996a2b40cSVivien Didelot u16 reg, ctrl; 18096a2b40cSVivien Didelot int err; 18196a2b40cSVivien Didelot 18296a2b40cSVivien Didelot switch (speed) { 18396a2b40cSVivien Didelot case 10: 18496a2b40cSVivien Didelot ctrl = PORT_PCS_CTRL_SPEED_10; 18596a2b40cSVivien Didelot break; 18696a2b40cSVivien Didelot case 100: 18796a2b40cSVivien Didelot ctrl = PORT_PCS_CTRL_SPEED_100; 18896a2b40cSVivien Didelot break; 18996a2b40cSVivien Didelot case 200: 19096a2b40cSVivien Didelot if (alt_bit) 19196a2b40cSVivien Didelot ctrl = PORT_PCS_CTRL_SPEED_100 | PORT_PCS_CTRL_ALTSPEED; 19296a2b40cSVivien Didelot else 19396a2b40cSVivien Didelot ctrl = PORT_PCS_CTRL_SPEED_200; 19496a2b40cSVivien Didelot break; 19596a2b40cSVivien Didelot case 1000: 19696a2b40cSVivien Didelot ctrl = PORT_PCS_CTRL_SPEED_1000; 19796a2b40cSVivien Didelot break; 19896a2b40cSVivien Didelot case 2500: 199740117a8SAndrew Lunn ctrl = PORT_PCS_CTRL_SPEED_10000 | PORT_PCS_CTRL_ALTSPEED; 20096a2b40cSVivien Didelot break; 20196a2b40cSVivien Didelot case 10000: 20296a2b40cSVivien Didelot /* all bits set, fall through... */ 20396a2b40cSVivien Didelot case SPEED_UNFORCED: 20496a2b40cSVivien Didelot ctrl = PORT_PCS_CTRL_SPEED_UNFORCED; 20596a2b40cSVivien Didelot break; 20696a2b40cSVivien Didelot default: 20796a2b40cSVivien Didelot return -EOPNOTSUPP; 20896a2b40cSVivien Didelot } 20996a2b40cSVivien Didelot 21096a2b40cSVivien Didelot err = mv88e6xxx_port_read(chip, port, PORT_PCS_CTRL, ®); 21196a2b40cSVivien Didelot if (err) 21296a2b40cSVivien Didelot return err; 21396a2b40cSVivien Didelot 21496a2b40cSVivien Didelot reg &= ~PORT_PCS_CTRL_SPEED_MASK; 21596a2b40cSVivien Didelot if (alt_bit) 21696a2b40cSVivien Didelot reg &= ~PORT_PCS_CTRL_ALTSPEED; 21796a2b40cSVivien Didelot if (force_bit) { 21896a2b40cSVivien Didelot reg &= ~PORT_PCS_CTRL_FORCE_SPEED; 2190b6e3d03SAndrew Lunn if (speed != SPEED_UNFORCED) 22096a2b40cSVivien Didelot ctrl |= PORT_PCS_CTRL_FORCE_SPEED; 22196a2b40cSVivien Didelot } 22296a2b40cSVivien Didelot reg |= ctrl; 22396a2b40cSVivien Didelot 22496a2b40cSVivien Didelot err = mv88e6xxx_port_write(chip, port, PORT_PCS_CTRL, reg); 22596a2b40cSVivien Didelot if (err) 22696a2b40cSVivien Didelot return err; 22796a2b40cSVivien Didelot 22896a2b40cSVivien Didelot if (speed) 22996a2b40cSVivien Didelot netdev_dbg(chip->ds->ports[port].netdev, 23096a2b40cSVivien Didelot "Speed set to %d Mbps\n", speed); 23196a2b40cSVivien Didelot else 23296a2b40cSVivien Didelot netdev_dbg(chip->ds->ports[port].netdev, "Speed unforced\n"); 23396a2b40cSVivien Didelot 23496a2b40cSVivien Didelot return 0; 23596a2b40cSVivien Didelot } 23696a2b40cSVivien Didelot 23796a2b40cSVivien Didelot /* Support 10, 100, 200 Mbps (e.g. 88E6065 family) */ 23896a2b40cSVivien Didelot int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 23996a2b40cSVivien Didelot { 24096a2b40cSVivien Didelot if (speed == SPEED_MAX) 24196a2b40cSVivien Didelot speed = 200; 24296a2b40cSVivien Didelot 24396a2b40cSVivien Didelot if (speed > 200) 24496a2b40cSVivien Didelot return -EOPNOTSUPP; 24596a2b40cSVivien Didelot 24696a2b40cSVivien Didelot /* Setting 200 Mbps on port 0 to 3 selects 100 Mbps */ 24796a2b40cSVivien Didelot return mv88e6xxx_port_set_speed(chip, port, speed, false, false); 24896a2b40cSVivien Didelot } 24996a2b40cSVivien Didelot 25096a2b40cSVivien Didelot /* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */ 25196a2b40cSVivien Didelot int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 25296a2b40cSVivien Didelot { 25396a2b40cSVivien Didelot if (speed == SPEED_MAX) 25496a2b40cSVivien Didelot speed = 1000; 25596a2b40cSVivien Didelot 25696a2b40cSVivien Didelot if (speed == 200 || speed > 1000) 25796a2b40cSVivien Didelot return -EOPNOTSUPP; 25896a2b40cSVivien Didelot 25996a2b40cSVivien Didelot return mv88e6xxx_port_set_speed(chip, port, speed, false, false); 26096a2b40cSVivien Didelot } 26196a2b40cSVivien Didelot 26296a2b40cSVivien Didelot /* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */ 26396a2b40cSVivien Didelot int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 26496a2b40cSVivien Didelot { 26596a2b40cSVivien Didelot if (speed == SPEED_MAX) 26696a2b40cSVivien Didelot speed = 1000; 26796a2b40cSVivien Didelot 26896a2b40cSVivien Didelot if (speed > 1000) 26996a2b40cSVivien Didelot return -EOPNOTSUPP; 27096a2b40cSVivien Didelot 27196a2b40cSVivien Didelot if (speed == 200 && port < 5) 27296a2b40cSVivien Didelot return -EOPNOTSUPP; 27396a2b40cSVivien Didelot 27496a2b40cSVivien Didelot return mv88e6xxx_port_set_speed(chip, port, speed, true, false); 27596a2b40cSVivien Didelot } 27696a2b40cSVivien Didelot 27796a2b40cSVivien Didelot /* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */ 27896a2b40cSVivien Didelot int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 27996a2b40cSVivien Didelot { 28096a2b40cSVivien Didelot if (speed == SPEED_MAX) 28196a2b40cSVivien Didelot speed = port < 9 ? 1000 : 2500; 28296a2b40cSVivien Didelot 28396a2b40cSVivien Didelot if (speed > 2500) 28496a2b40cSVivien Didelot return -EOPNOTSUPP; 28596a2b40cSVivien Didelot 28696a2b40cSVivien Didelot if (speed == 200 && port != 0) 28796a2b40cSVivien Didelot return -EOPNOTSUPP; 28896a2b40cSVivien Didelot 28996a2b40cSVivien Didelot if (speed == 2500 && port < 9) 29096a2b40cSVivien Didelot return -EOPNOTSUPP; 29196a2b40cSVivien Didelot 29296a2b40cSVivien Didelot return mv88e6xxx_port_set_speed(chip, port, speed, true, true); 29396a2b40cSVivien Didelot } 29496a2b40cSVivien Didelot 29596a2b40cSVivien Didelot /* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */ 29696a2b40cSVivien Didelot int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) 29796a2b40cSVivien Didelot { 29896a2b40cSVivien Didelot if (speed == SPEED_MAX) 29996a2b40cSVivien Didelot speed = port < 9 ? 1000 : 10000; 30096a2b40cSVivien Didelot 30196a2b40cSVivien Didelot if (speed == 200 && port != 0) 30296a2b40cSVivien Didelot return -EOPNOTSUPP; 30396a2b40cSVivien Didelot 30496a2b40cSVivien Didelot if (speed >= 2500 && port < 9) 30596a2b40cSVivien Didelot return -EOPNOTSUPP; 30696a2b40cSVivien Didelot 30796a2b40cSVivien Didelot return mv88e6xxx_port_set_speed(chip, port, speed, true, true); 30896a2b40cSVivien Didelot } 30996a2b40cSVivien Didelot 310f39908d3SAndrew Lunn int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, 311f39908d3SAndrew Lunn phy_interface_t mode) 312f39908d3SAndrew Lunn { 313f39908d3SAndrew Lunn u16 reg; 314f39908d3SAndrew Lunn u16 cmode; 315f39908d3SAndrew Lunn int err; 316f39908d3SAndrew Lunn 317f39908d3SAndrew Lunn if (mode == PHY_INTERFACE_MODE_NA) 318f39908d3SAndrew Lunn return 0; 319f39908d3SAndrew Lunn 320f39908d3SAndrew Lunn if (port != 9 && port != 10) 321f39908d3SAndrew Lunn return -EOPNOTSUPP; 322f39908d3SAndrew Lunn 323f39908d3SAndrew Lunn switch (mode) { 324f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_1000BASEX: 325f39908d3SAndrew Lunn cmode = PORT_STATUS_CMODE_1000BASE_X; 326f39908d3SAndrew Lunn break; 327f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_SGMII: 328f39908d3SAndrew Lunn cmode = PORT_STATUS_CMODE_SGMII; 329f39908d3SAndrew Lunn break; 330f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_2500BASEX: 331f39908d3SAndrew Lunn cmode = PORT_STATUS_CMODE_2500BASEX; 332f39908d3SAndrew Lunn break; 333f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_XGMII: 334f39908d3SAndrew Lunn cmode = PORT_STATUS_CMODE_XAUI; 335f39908d3SAndrew Lunn break; 336f39908d3SAndrew Lunn case PHY_INTERFACE_MODE_RXAUI: 337f39908d3SAndrew Lunn cmode = PORT_STATUS_CMODE_RXAUI; 338f39908d3SAndrew Lunn break; 339f39908d3SAndrew Lunn default: 340f39908d3SAndrew Lunn cmode = 0; 341f39908d3SAndrew Lunn } 342f39908d3SAndrew Lunn 343f39908d3SAndrew Lunn if (cmode) { 344f39908d3SAndrew Lunn err = mv88e6xxx_port_read(chip, port, PORT_STATUS, ®); 345f39908d3SAndrew Lunn if (err) 346f39908d3SAndrew Lunn return err; 347f39908d3SAndrew Lunn 348f39908d3SAndrew Lunn reg &= ~PORT_STATUS_CMODE_MASK; 349f39908d3SAndrew Lunn reg |= cmode; 350f39908d3SAndrew Lunn 351f39908d3SAndrew Lunn err = mv88e6xxx_port_write(chip, port, PORT_STATUS, reg); 352f39908d3SAndrew Lunn if (err) 353f39908d3SAndrew Lunn return err; 354f39908d3SAndrew Lunn } 355f39908d3SAndrew Lunn 356f39908d3SAndrew Lunn return 0; 357f39908d3SAndrew Lunn } 358f39908d3SAndrew Lunn 359f39908d3SAndrew Lunn int mv88e6xxx_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode) 360f39908d3SAndrew Lunn { 361f39908d3SAndrew Lunn int err; 362f39908d3SAndrew Lunn u16 reg; 363f39908d3SAndrew Lunn 364f39908d3SAndrew Lunn err = mv88e6xxx_port_read(chip, port, PORT_STATUS, ®); 365f39908d3SAndrew Lunn if (err) 366f39908d3SAndrew Lunn return err; 367f39908d3SAndrew Lunn 368f39908d3SAndrew Lunn *cmode = reg & PORT_STATUS_CMODE_MASK; 369f39908d3SAndrew Lunn 370f39908d3SAndrew Lunn return 0; 371f39908d3SAndrew Lunn } 372f39908d3SAndrew Lunn 373b35d322aSAndrew Lunn /* Offset 0x02: Pause Control 374b35d322aSAndrew Lunn * 375b35d322aSAndrew Lunn * Do not limit the period of time that this port can be paused for by 376b35d322aSAndrew Lunn * the remote end or the period of time that this port can pause the 377b35d322aSAndrew Lunn * remote end. 378b35d322aSAndrew Lunn */ 379b35d322aSAndrew Lunn int mv88e6097_port_pause_config(struct mv88e6xxx_chip *chip, int port) 380b35d322aSAndrew Lunn { 381b35d322aSAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_PAUSE_CTRL, 0x0000); 382b35d322aSAndrew Lunn } 383b35d322aSAndrew Lunn 3843ce0e65eSAndrew Lunn int mv88e6390_port_pause_config(struct mv88e6xxx_chip *chip, int port) 3853ce0e65eSAndrew Lunn { 3863ce0e65eSAndrew Lunn int err; 3873ce0e65eSAndrew Lunn 3883ce0e65eSAndrew Lunn err = mv88e6xxx_port_write(chip, port, PORT_PAUSE_CTRL, 3893ce0e65eSAndrew Lunn PORT_FLOW_CTRL_LIMIT_IN | 0); 3903ce0e65eSAndrew Lunn if (err) 3913ce0e65eSAndrew Lunn return err; 3923ce0e65eSAndrew Lunn 3933ce0e65eSAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_PAUSE_CTRL, 3943ce0e65eSAndrew Lunn PORT_FLOW_CTRL_LIMIT_OUT | 0); 3953ce0e65eSAndrew Lunn } 3963ce0e65eSAndrew Lunn 397e28def33SVivien Didelot /* Offset 0x04: Port Control Register */ 398e28def33SVivien Didelot 399e28def33SVivien Didelot static const char * const mv88e6xxx_port_state_names[] = { 400e28def33SVivien Didelot [PORT_CONTROL_STATE_DISABLED] = "Disabled", 401e28def33SVivien Didelot [PORT_CONTROL_STATE_BLOCKING] = "Blocking/Listening", 402e28def33SVivien Didelot [PORT_CONTROL_STATE_LEARNING] = "Learning", 403e28def33SVivien Didelot [PORT_CONTROL_STATE_FORWARDING] = "Forwarding", 404e28def33SVivien Didelot }; 405e28def33SVivien Didelot 406e28def33SVivien Didelot int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state) 407e28def33SVivien Didelot { 408e28def33SVivien Didelot u16 reg; 409e28def33SVivien Didelot int err; 410e28def33SVivien Didelot 411e28def33SVivien Didelot err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®); 412e28def33SVivien Didelot if (err) 413e28def33SVivien Didelot return err; 414e28def33SVivien Didelot 415e28def33SVivien Didelot reg &= ~PORT_CONTROL_STATE_MASK; 416e28def33SVivien Didelot reg |= state; 417e28def33SVivien Didelot 418e28def33SVivien Didelot err = mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); 419e28def33SVivien Didelot if (err) 420e28def33SVivien Didelot return err; 421e28def33SVivien Didelot 422e28def33SVivien Didelot netdev_dbg(chip->ds->ports[port].netdev, "PortState set to %s\n", 423e28def33SVivien Didelot mv88e6xxx_port_state_names[state]); 424e28def33SVivien Didelot 425e28def33SVivien Didelot return 0; 426e28def33SVivien Didelot } 4275a7921f4SVivien Didelot 42856995cbcSAndrew Lunn int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port, 42956995cbcSAndrew Lunn u16 mode) 43056995cbcSAndrew Lunn { 43156995cbcSAndrew Lunn int err; 43256995cbcSAndrew Lunn u16 reg; 43356995cbcSAndrew Lunn 43456995cbcSAndrew Lunn err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®); 43556995cbcSAndrew Lunn if (err) 43656995cbcSAndrew Lunn return err; 43756995cbcSAndrew Lunn 43856995cbcSAndrew Lunn reg &= ~PORT_CONTROL_EGRESS_MASK; 43956995cbcSAndrew Lunn reg |= mode; 44056995cbcSAndrew Lunn 44156995cbcSAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); 44256995cbcSAndrew Lunn } 44356995cbcSAndrew Lunn 44456995cbcSAndrew Lunn int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, 44556995cbcSAndrew Lunn enum mv88e6xxx_frame_mode mode) 44656995cbcSAndrew Lunn { 44756995cbcSAndrew Lunn int err; 44856995cbcSAndrew Lunn u16 reg; 44956995cbcSAndrew Lunn 45056995cbcSAndrew Lunn err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®); 45156995cbcSAndrew Lunn if (err) 45256995cbcSAndrew Lunn return err; 45356995cbcSAndrew Lunn 45456995cbcSAndrew Lunn reg &= ~PORT_CONTROL_FRAME_MODE_DSA; 45556995cbcSAndrew Lunn 45656995cbcSAndrew Lunn switch (mode) { 45756995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_NORMAL: 45856995cbcSAndrew Lunn reg |= PORT_CONTROL_FRAME_MODE_NORMAL; 45956995cbcSAndrew Lunn break; 46056995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_DSA: 46156995cbcSAndrew Lunn reg |= PORT_CONTROL_FRAME_MODE_DSA; 46256995cbcSAndrew Lunn break; 46356995cbcSAndrew Lunn default: 46456995cbcSAndrew Lunn return -EINVAL; 46556995cbcSAndrew Lunn } 46656995cbcSAndrew Lunn 46756995cbcSAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); 46856995cbcSAndrew Lunn } 46956995cbcSAndrew Lunn 47056995cbcSAndrew Lunn int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, 47156995cbcSAndrew Lunn enum mv88e6xxx_frame_mode mode) 47256995cbcSAndrew Lunn { 47356995cbcSAndrew Lunn int err; 47456995cbcSAndrew Lunn u16 reg; 47556995cbcSAndrew Lunn 47656995cbcSAndrew Lunn err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®); 47756995cbcSAndrew Lunn if (err) 47856995cbcSAndrew Lunn return err; 47956995cbcSAndrew Lunn 48056995cbcSAndrew Lunn reg &= ~PORT_CONTROL_FRAME_MASK; 48156995cbcSAndrew Lunn 48256995cbcSAndrew Lunn switch (mode) { 48356995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_NORMAL: 48456995cbcSAndrew Lunn reg |= PORT_CONTROL_FRAME_MODE_NORMAL; 48556995cbcSAndrew Lunn break; 48656995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_DSA: 48756995cbcSAndrew Lunn reg |= PORT_CONTROL_FRAME_MODE_DSA; 48856995cbcSAndrew Lunn break; 48956995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_PROVIDER: 49056995cbcSAndrew Lunn reg |= PORT_CONTROL_FRAME_MODE_PROVIDER; 49156995cbcSAndrew Lunn break; 49256995cbcSAndrew Lunn case MV88E6XXX_FRAME_MODE_ETHERTYPE: 49356995cbcSAndrew Lunn reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA; 49456995cbcSAndrew Lunn break; 49556995cbcSAndrew Lunn default: 49656995cbcSAndrew Lunn return -EINVAL; 49756995cbcSAndrew Lunn } 49856995cbcSAndrew Lunn 49956995cbcSAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); 50056995cbcSAndrew Lunn } 50156995cbcSAndrew Lunn 502601aeed3SVivien Didelot static int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip, 503601aeed3SVivien Didelot int port, bool unicast) 50456995cbcSAndrew Lunn { 50556995cbcSAndrew Lunn int err; 50656995cbcSAndrew Lunn u16 reg; 50756995cbcSAndrew Lunn 50856995cbcSAndrew Lunn err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®); 50956995cbcSAndrew Lunn if (err) 51056995cbcSAndrew Lunn return err; 51156995cbcSAndrew Lunn 512601aeed3SVivien Didelot if (unicast) 51356995cbcSAndrew Lunn reg |= PORT_CONTROL_FORWARD_UNKNOWN; 51456995cbcSAndrew Lunn else 51556995cbcSAndrew Lunn reg &= ~PORT_CONTROL_FORWARD_UNKNOWN; 51656995cbcSAndrew Lunn 51756995cbcSAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); 51856995cbcSAndrew Lunn } 51956995cbcSAndrew Lunn 520601aeed3SVivien Didelot int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, 521601aeed3SVivien Didelot bool unicast, bool multicast) 52256995cbcSAndrew Lunn { 52356995cbcSAndrew Lunn int err; 52456995cbcSAndrew Lunn u16 reg; 52556995cbcSAndrew Lunn 52656995cbcSAndrew Lunn err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, ®); 52756995cbcSAndrew Lunn if (err) 52856995cbcSAndrew Lunn return err; 52956995cbcSAndrew Lunn 530601aeed3SVivien Didelot reg &= ~PORT_CONTROL_EGRESS_FLOODS_MASK; 531601aeed3SVivien Didelot 532601aeed3SVivien Didelot if (unicast && multicast) 533601aeed3SVivien Didelot reg |= PORT_CONTROL_EGRESS_FLOODS_ALL_UNKNOWN_DA; 534601aeed3SVivien Didelot else if (unicast) 535601aeed3SVivien Didelot reg |= PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_MC_DA; 536601aeed3SVivien Didelot else if (multicast) 537601aeed3SVivien Didelot reg |= PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_UC_DA; 53856995cbcSAndrew Lunn else 539601aeed3SVivien Didelot reg |= PORT_CONTROL_EGRESS_FLOODS_NO_UNKNOWN_DA; 54056995cbcSAndrew Lunn 54156995cbcSAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg); 54256995cbcSAndrew Lunn } 54356995cbcSAndrew Lunn 544b4e48c50SVivien Didelot /* Offset 0x05: Port Control 1 */ 545b4e48c50SVivien Didelot 546ea698f4fSVivien Didelot int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port, 547ea698f4fSVivien Didelot bool message_port) 548ea698f4fSVivien Didelot { 549ea698f4fSVivien Didelot u16 val; 550ea698f4fSVivien Didelot int err; 551ea698f4fSVivien Didelot 552ea698f4fSVivien Didelot err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_1, &val); 553ea698f4fSVivien Didelot if (err) 554ea698f4fSVivien Didelot return err; 555ea698f4fSVivien Didelot 556ea698f4fSVivien Didelot if (message_port) 557ea698f4fSVivien Didelot val |= PORT_CONTROL_1_MESSAGE_PORT; 558ea698f4fSVivien Didelot else 559ea698f4fSVivien Didelot val &= ~PORT_CONTROL_1_MESSAGE_PORT; 560ea698f4fSVivien Didelot 561ea698f4fSVivien Didelot return mv88e6xxx_port_write(chip, port, PORT_CONTROL_1, val); 562ea698f4fSVivien Didelot } 563ea698f4fSVivien Didelot 5645a7921f4SVivien Didelot /* Offset 0x06: Port Based VLAN Map */ 5655a7921f4SVivien Didelot 5665a7921f4SVivien Didelot int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map) 5675a7921f4SVivien Didelot { 5684d294af2SVivien Didelot const u16 mask = mv88e6xxx_port_mask(chip); 5695a7921f4SVivien Didelot u16 reg; 5705a7921f4SVivien Didelot int err; 5715a7921f4SVivien Didelot 5725a7921f4SVivien Didelot err = mv88e6xxx_port_read(chip, port, PORT_BASE_VLAN, ®); 5735a7921f4SVivien Didelot if (err) 5745a7921f4SVivien Didelot return err; 5755a7921f4SVivien Didelot 5765a7921f4SVivien Didelot reg &= ~mask; 5775a7921f4SVivien Didelot reg |= map & mask; 5785a7921f4SVivien Didelot 5795a7921f4SVivien Didelot err = mv88e6xxx_port_write(chip, port, PORT_BASE_VLAN, reg); 5805a7921f4SVivien Didelot if (err) 5815a7921f4SVivien Didelot return err; 5825a7921f4SVivien Didelot 5835a7921f4SVivien Didelot netdev_dbg(chip->ds->ports[port].netdev, "VLANTable set to %.3x\n", 5845a7921f4SVivien Didelot map); 5855a7921f4SVivien Didelot 5865a7921f4SVivien Didelot return 0; 5875a7921f4SVivien Didelot } 588b4e48c50SVivien Didelot 589b4e48c50SVivien Didelot int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid) 590b4e48c50SVivien Didelot { 591b4e48c50SVivien Didelot const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4; 592b4e48c50SVivien Didelot u16 reg; 593b4e48c50SVivien Didelot int err; 594b4e48c50SVivien Didelot 595b4e48c50SVivien Didelot /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */ 596b4e48c50SVivien Didelot err = mv88e6xxx_port_read(chip, port, PORT_BASE_VLAN, ®); 597b4e48c50SVivien Didelot if (err) 598b4e48c50SVivien Didelot return err; 599b4e48c50SVivien Didelot 600b4e48c50SVivien Didelot *fid = (reg & 0xf000) >> 12; 601b4e48c50SVivien Didelot 602b4e48c50SVivien Didelot /* Port's default FID upper bits are located in reg 0x05, offset 0 */ 603b4e48c50SVivien Didelot if (upper_mask) { 604b4e48c50SVivien Didelot err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_1, ®); 605b4e48c50SVivien Didelot if (err) 606b4e48c50SVivien Didelot return err; 607b4e48c50SVivien Didelot 608b4e48c50SVivien Didelot *fid |= (reg & upper_mask) << 4; 609b4e48c50SVivien Didelot } 610b4e48c50SVivien Didelot 611b4e48c50SVivien Didelot return 0; 612b4e48c50SVivien Didelot } 613b4e48c50SVivien Didelot 614b4e48c50SVivien Didelot int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid) 615b4e48c50SVivien Didelot { 616b4e48c50SVivien Didelot const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4; 617b4e48c50SVivien Didelot u16 reg; 618b4e48c50SVivien Didelot int err; 619b4e48c50SVivien Didelot 620b4e48c50SVivien Didelot if (fid >= mv88e6xxx_num_databases(chip)) 621b4e48c50SVivien Didelot return -EINVAL; 622b4e48c50SVivien Didelot 623b4e48c50SVivien Didelot /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */ 624b4e48c50SVivien Didelot err = mv88e6xxx_port_read(chip, port, PORT_BASE_VLAN, ®); 625b4e48c50SVivien Didelot if (err) 626b4e48c50SVivien Didelot return err; 627b4e48c50SVivien Didelot 628b4e48c50SVivien Didelot reg &= 0x0fff; 629b4e48c50SVivien Didelot reg |= (fid & 0x000f) << 12; 630b4e48c50SVivien Didelot 631b4e48c50SVivien Didelot err = mv88e6xxx_port_write(chip, port, PORT_BASE_VLAN, reg); 632b4e48c50SVivien Didelot if (err) 633b4e48c50SVivien Didelot return err; 634b4e48c50SVivien Didelot 635b4e48c50SVivien Didelot /* Port's default FID upper bits are located in reg 0x05, offset 0 */ 636b4e48c50SVivien Didelot if (upper_mask) { 637b4e48c50SVivien Didelot err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_1, ®); 638b4e48c50SVivien Didelot if (err) 639b4e48c50SVivien Didelot return err; 640b4e48c50SVivien Didelot 641b4e48c50SVivien Didelot reg &= ~upper_mask; 642b4e48c50SVivien Didelot reg |= (fid >> 4) & upper_mask; 643b4e48c50SVivien Didelot 644b4e48c50SVivien Didelot err = mv88e6xxx_port_write(chip, port, PORT_CONTROL_1, reg); 645b4e48c50SVivien Didelot if (err) 646b4e48c50SVivien Didelot return err; 647b4e48c50SVivien Didelot } 648b4e48c50SVivien Didelot 649b4e48c50SVivien Didelot netdev_dbg(chip->ds->ports[port].netdev, "FID set to %u\n", fid); 650b4e48c50SVivien Didelot 651b4e48c50SVivien Didelot return 0; 652b4e48c50SVivien Didelot } 65377064f37SVivien Didelot 65477064f37SVivien Didelot /* Offset 0x07: Default Port VLAN ID & Priority */ 65577064f37SVivien Didelot 65677064f37SVivien Didelot int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid) 65777064f37SVivien Didelot { 65877064f37SVivien Didelot u16 reg; 65977064f37SVivien Didelot int err; 66077064f37SVivien Didelot 66177064f37SVivien Didelot err = mv88e6xxx_port_read(chip, port, PORT_DEFAULT_VLAN, ®); 66277064f37SVivien Didelot if (err) 66377064f37SVivien Didelot return err; 66477064f37SVivien Didelot 66577064f37SVivien Didelot *pvid = reg & PORT_DEFAULT_VLAN_MASK; 66677064f37SVivien Didelot 66777064f37SVivien Didelot return 0; 66877064f37SVivien Didelot } 66977064f37SVivien Didelot 67077064f37SVivien Didelot int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid) 67177064f37SVivien Didelot { 67277064f37SVivien Didelot u16 reg; 67377064f37SVivien Didelot int err; 67477064f37SVivien Didelot 67577064f37SVivien Didelot err = mv88e6xxx_port_read(chip, port, PORT_DEFAULT_VLAN, ®); 67677064f37SVivien Didelot if (err) 67777064f37SVivien Didelot return err; 67877064f37SVivien Didelot 67977064f37SVivien Didelot reg &= ~PORT_DEFAULT_VLAN_MASK; 68077064f37SVivien Didelot reg |= pvid & PORT_DEFAULT_VLAN_MASK; 68177064f37SVivien Didelot 68277064f37SVivien Didelot err = mv88e6xxx_port_write(chip, port, PORT_DEFAULT_VLAN, reg); 68377064f37SVivien Didelot if (err) 68477064f37SVivien Didelot return err; 68577064f37SVivien Didelot 68677064f37SVivien Didelot netdev_dbg(chip->ds->ports[port].netdev, "DefaultVID set to %u\n", 68777064f37SVivien Didelot pvid); 68877064f37SVivien Didelot 68977064f37SVivien Didelot return 0; 69077064f37SVivien Didelot } 691385a0995SVivien Didelot 692385a0995SVivien Didelot /* Offset 0x08: Port Control 2 Register */ 693385a0995SVivien Didelot 694385a0995SVivien Didelot static const char * const mv88e6xxx_port_8021q_mode_names[] = { 695385a0995SVivien Didelot [PORT_CONTROL_2_8021Q_DISABLED] = "Disabled", 696385a0995SVivien Didelot [PORT_CONTROL_2_8021Q_FALLBACK] = "Fallback", 697385a0995SVivien Didelot [PORT_CONTROL_2_8021Q_CHECK] = "Check", 698385a0995SVivien Didelot [PORT_CONTROL_2_8021Q_SECURE] = "Secure", 699385a0995SVivien Didelot }; 700385a0995SVivien Didelot 701601aeed3SVivien Didelot static int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip, 702601aeed3SVivien Didelot int port, bool multicast) 703a23b2961SAndrew Lunn { 704a23b2961SAndrew Lunn int err; 705a23b2961SAndrew Lunn u16 reg; 706a23b2961SAndrew Lunn 707a23b2961SAndrew Lunn err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_2, ®); 708a23b2961SAndrew Lunn if (err) 709a23b2961SAndrew Lunn return err; 710a23b2961SAndrew Lunn 711601aeed3SVivien Didelot if (multicast) 712601aeed3SVivien Didelot reg |= PORT_CONTROL_2_DEFAULT_FORWARD; 713a23b2961SAndrew Lunn else 714601aeed3SVivien Didelot reg &= ~PORT_CONTROL_2_DEFAULT_FORWARD; 715a23b2961SAndrew Lunn 716a23b2961SAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg); 717a23b2961SAndrew Lunn } 718a23b2961SAndrew Lunn 719601aeed3SVivien Didelot int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, 720601aeed3SVivien Didelot bool unicast, bool multicast) 721601aeed3SVivien Didelot { 722601aeed3SVivien Didelot int err; 723601aeed3SVivien Didelot 724601aeed3SVivien Didelot err = mv88e6185_port_set_forward_unknown(chip, port, unicast); 725601aeed3SVivien Didelot if (err) 726601aeed3SVivien Didelot return err; 727601aeed3SVivien Didelot 728601aeed3SVivien Didelot return mv88e6185_port_set_default_forward(chip, port, multicast); 729601aeed3SVivien Didelot } 730601aeed3SVivien Didelot 731a23b2961SAndrew Lunn int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port, 732a23b2961SAndrew Lunn int upstream_port) 733a23b2961SAndrew Lunn { 734a23b2961SAndrew Lunn int err; 735a23b2961SAndrew Lunn u16 reg; 736a23b2961SAndrew Lunn 737a23b2961SAndrew Lunn err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_2, ®); 738a23b2961SAndrew Lunn if (err) 739a23b2961SAndrew Lunn return err; 740a23b2961SAndrew Lunn 741a23b2961SAndrew Lunn reg &= ~PORT_CONTROL_2_UPSTREAM_MASK; 742a23b2961SAndrew Lunn reg |= upstream_port; 743a23b2961SAndrew Lunn 744a23b2961SAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg); 745a23b2961SAndrew Lunn } 746a23b2961SAndrew Lunn 747385a0995SVivien Didelot int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port, 748385a0995SVivien Didelot u16 mode) 749385a0995SVivien Didelot { 750385a0995SVivien Didelot u16 reg; 751385a0995SVivien Didelot int err; 752385a0995SVivien Didelot 753385a0995SVivien Didelot err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_2, ®); 754385a0995SVivien Didelot if (err) 755385a0995SVivien Didelot return err; 756385a0995SVivien Didelot 757385a0995SVivien Didelot reg &= ~PORT_CONTROL_2_8021Q_MASK; 758385a0995SVivien Didelot reg |= mode & PORT_CONTROL_2_8021Q_MASK; 759385a0995SVivien Didelot 760385a0995SVivien Didelot err = mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg); 761385a0995SVivien Didelot if (err) 762385a0995SVivien Didelot return err; 763385a0995SVivien Didelot 764385a0995SVivien Didelot netdev_dbg(chip->ds->ports[port].netdev, "802.1QMode set to %s\n", 765385a0995SVivien Didelot mv88e6xxx_port_8021q_mode_names[mode]); 766385a0995SVivien Didelot 767385a0995SVivien Didelot return 0; 768385a0995SVivien Didelot } 769ef0a7318SAndrew Lunn 770a23b2961SAndrew Lunn int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port) 771a23b2961SAndrew Lunn { 772a23b2961SAndrew Lunn u16 reg; 773a23b2961SAndrew Lunn int err; 774a23b2961SAndrew Lunn 775a23b2961SAndrew Lunn err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_2, ®); 776a23b2961SAndrew Lunn if (err) 777a23b2961SAndrew Lunn return err; 778a23b2961SAndrew Lunn 779a23b2961SAndrew Lunn reg |= PORT_CONTROL_2_MAP_DA; 780a23b2961SAndrew Lunn 781a23b2961SAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg); 782a23b2961SAndrew Lunn } 783a23b2961SAndrew Lunn 7845f436666SAndrew Lunn int mv88e6165_port_jumbo_config(struct mv88e6xxx_chip *chip, int port) 7855f436666SAndrew Lunn { 7865f436666SAndrew Lunn u16 reg; 7875f436666SAndrew Lunn int err; 7885f436666SAndrew Lunn 7895f436666SAndrew Lunn err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_2, ®); 7905f436666SAndrew Lunn if (err) 7915f436666SAndrew Lunn return err; 7925f436666SAndrew Lunn 7935f436666SAndrew Lunn reg |= PORT_CONTROL_2_JUMBO_10240; 7945f436666SAndrew Lunn 7955f436666SAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_CONTROL_2, reg); 7965f436666SAndrew Lunn } 7975f436666SAndrew Lunn 798ef70b111SAndrew Lunn /* Offset 0x09: Port Rate Control */ 799ef70b111SAndrew Lunn 800ef70b111SAndrew Lunn int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port) 801ef70b111SAndrew Lunn { 802ef70b111SAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_RATE_CONTROL, 0x0000); 803ef70b111SAndrew Lunn } 804ef70b111SAndrew Lunn 805ef70b111SAndrew Lunn int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port) 806ef70b111SAndrew Lunn { 807ef70b111SAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_RATE_CONTROL, 0x0001); 808ef70b111SAndrew Lunn } 809ef70b111SAndrew Lunn 810c8c94891SVivien Didelot /* Offset 0x0C: Port ATU Control */ 811c8c94891SVivien Didelot 812c8c94891SVivien Didelot int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port) 813c8c94891SVivien Didelot { 814c8c94891SVivien Didelot return mv88e6xxx_port_write(chip, port, PORT_ATU_CONTROL, 0); 815c8c94891SVivien Didelot } 816c8c94891SVivien Didelot 8179dbfb4e1SVivien Didelot /* Offset 0x0D: (Priority) Override Register */ 8189dbfb4e1SVivien Didelot 8199dbfb4e1SVivien Didelot int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port) 8209dbfb4e1SVivien Didelot { 8219dbfb4e1SVivien Didelot return mv88e6xxx_port_write(chip, port, PORT_PRI_OVERRIDE, 0); 8229dbfb4e1SVivien Didelot } 8239dbfb4e1SVivien Didelot 82456995cbcSAndrew Lunn /* Offset 0x0f: Port Ether type */ 82556995cbcSAndrew Lunn 82656995cbcSAndrew Lunn int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port, 82756995cbcSAndrew Lunn u16 etype) 82856995cbcSAndrew Lunn { 82956995cbcSAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_ETH_TYPE, etype); 83056995cbcSAndrew Lunn } 83156995cbcSAndrew Lunn 832ef0a7318SAndrew Lunn /* Offset 0x18: Port IEEE Priority Remapping Registers [0-3] 833ef0a7318SAndrew Lunn * Offset 0x19: Port IEEE Priority Remapping Registers [4-7] 834ef0a7318SAndrew Lunn */ 835ef0a7318SAndrew Lunn 836ef0a7318SAndrew Lunn int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port) 837ef0a7318SAndrew Lunn { 838ef0a7318SAndrew Lunn int err; 839ef0a7318SAndrew Lunn 840ef0a7318SAndrew Lunn /* Use a direct priority mapping for all IEEE tagged frames */ 841ef0a7318SAndrew Lunn err = mv88e6xxx_port_write(chip, port, PORT_TAG_REGMAP_0123, 0x3210); 842ef0a7318SAndrew Lunn if (err) 843ef0a7318SAndrew Lunn return err; 844ef0a7318SAndrew Lunn 845ef0a7318SAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_TAG_REGMAP_4567, 0x7654); 846ef0a7318SAndrew Lunn } 847ef0a7318SAndrew Lunn 848ef0a7318SAndrew Lunn static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip, 849ef0a7318SAndrew Lunn int port, u16 table, 850ef0a7318SAndrew Lunn u8 pointer, u16 data) 851ef0a7318SAndrew Lunn { 852ef0a7318SAndrew Lunn u16 reg; 853ef0a7318SAndrew Lunn 854ef0a7318SAndrew Lunn reg = PORT_IEEE_PRIO_MAP_TABLE_UPDATE | 855ef0a7318SAndrew Lunn table | 856ef0a7318SAndrew Lunn (pointer << PORT_IEEE_PRIO_MAP_TABLE_POINTER_SHIFT) | 857ef0a7318SAndrew Lunn data; 858ef0a7318SAndrew Lunn 859ef0a7318SAndrew Lunn return mv88e6xxx_port_write(chip, port, PORT_IEEE_PRIO_MAP_TABLE, reg); 860ef0a7318SAndrew Lunn } 861ef0a7318SAndrew Lunn 862ef0a7318SAndrew Lunn int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port) 863ef0a7318SAndrew Lunn { 864ef0a7318SAndrew Lunn int err, i; 865ef0a7318SAndrew Lunn 866ef0a7318SAndrew Lunn for (i = 0; i <= 7; i++) { 867ef0a7318SAndrew Lunn err = mv88e6xxx_port_ieeepmt_write( 868ef0a7318SAndrew Lunn chip, port, PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP, 869ef0a7318SAndrew Lunn i, (i | i << 4)); 870ef0a7318SAndrew Lunn if (err) 871ef0a7318SAndrew Lunn return err; 872ef0a7318SAndrew Lunn 873ef0a7318SAndrew Lunn err = mv88e6xxx_port_ieeepmt_write( 874ef0a7318SAndrew Lunn chip, port, PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP, 875ef0a7318SAndrew Lunn i, i); 876ef0a7318SAndrew Lunn if (err) 877ef0a7318SAndrew Lunn return err; 878ef0a7318SAndrew Lunn 879ef0a7318SAndrew Lunn err = mv88e6xxx_port_ieeepmt_write( 880ef0a7318SAndrew Lunn chip, port, PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP, 881ef0a7318SAndrew Lunn i, i); 882ef0a7318SAndrew Lunn if (err) 883ef0a7318SAndrew Lunn return err; 884ef0a7318SAndrew Lunn 885ef0a7318SAndrew Lunn err = mv88e6xxx_port_ieeepmt_write( 886ef0a7318SAndrew Lunn chip, port, PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP, 887ef0a7318SAndrew Lunn i, i); 888ef0a7318SAndrew Lunn if (err) 889ef0a7318SAndrew Lunn return err; 890ef0a7318SAndrew Lunn } 891ef0a7318SAndrew Lunn 892ef0a7318SAndrew Lunn return 0; 893ef0a7318SAndrew Lunn } 894