18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Marvell 88E6xxx Switch Port Registers support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2008 Marvell Semiconductor 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2016-2017 Savoir-faire Linux Inc. 88c2ecf20Sopenharmony_ci * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 128c2ecf20Sopenharmony_ci#include <linux/if_bridge.h> 138c2ecf20Sopenharmony_ci#include <linux/phy.h> 148c2ecf20Sopenharmony_ci#include <linux/phylink.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "chip.h" 178c2ecf20Sopenharmony_ci#include "port.h" 188c2ecf20Sopenharmony_ci#include "serdes.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciint mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg, 218c2ecf20Sopenharmony_ci u16 *val) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci int addr = chip->info->port_base_addr + port; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci return mv88e6xxx_read(chip, addr, reg, val); 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ciint mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg, 298c2ecf20Sopenharmony_ci u16 val) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci int addr = chip->info->port_base_addr + port; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci return mv88e6xxx_write(chip, addr, reg, val); 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* Offset 0x00: MAC (or PCS or Physical) Status Register 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * For most devices, this is read only. However the 6185 has the MyPause 398c2ecf20Sopenharmony_ci * bit read/write. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ciint mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port, 428c2ecf20Sopenharmony_ci int pause) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci u16 reg; 458c2ecf20Sopenharmony_ci int err; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 488c2ecf20Sopenharmony_ci if (err) 498c2ecf20Sopenharmony_ci return err; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (pause) 528c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_STS_MY_PAUSE; 538c2ecf20Sopenharmony_ci else 548c2ecf20Sopenharmony_ci reg &= ~MV88E6XXX_PORT_STS_MY_PAUSE; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* Offset 0x01: MAC (or PCS or Physical) Control Register 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * Link, Duplex and Flow Control have one force bit, one value bit. 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * For port's MAC speed, ForceSpd (or SpdValue) bits 1:0 program the value. 648c2ecf20Sopenharmony_ci * Alternative values require the 200BASE (or AltSpeed) bit 12 set. 658c2ecf20Sopenharmony_ci * Newer chips need a ForcedSpd bit 13 set to consider the value. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, 698c2ecf20Sopenharmony_ci phy_interface_t mode) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci u16 reg; 728c2ecf20Sopenharmony_ci int err; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); 758c2ecf20Sopenharmony_ci if (err) 768c2ecf20Sopenharmony_ci return err; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci reg &= ~(MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK | 798c2ecf20Sopenharmony_ci MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci switch (mode) { 828c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_RXID: 838c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK; 848c2ecf20Sopenharmony_ci break; 858c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_TXID: 868c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK; 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_ID: 898c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK | 908c2ecf20Sopenharmony_ci MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK; 918c2ecf20Sopenharmony_ci break; 928c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII: 938c2ecf20Sopenharmony_ci break; 948c2ecf20Sopenharmony_ci default: 958c2ecf20Sopenharmony_ci return 0; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg); 998c2ecf20Sopenharmony_ci if (err) 1008c2ecf20Sopenharmony_ci return err; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "p%d: delay RXCLK %s, TXCLK %s\n", port, 1038c2ecf20Sopenharmony_ci reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK ? "yes" : "no", 1048c2ecf20Sopenharmony_ci reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK ? "yes" : "no"); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return 0; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ciint mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, 1108c2ecf20Sopenharmony_ci phy_interface_t mode) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci if (port < 5) 1138c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return mv88e6xxx_port_set_rgmii_delay(chip, port, mode); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ciint mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, 1198c2ecf20Sopenharmony_ci phy_interface_t mode) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci if (port != 0) 1228c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return mv88e6xxx_port_set_rgmii_delay(chip, port, mode); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ciint mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci u16 reg; 1308c2ecf20Sopenharmony_ci int err; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); 1338c2ecf20Sopenharmony_ci if (err) 1348c2ecf20Sopenharmony_ci return err; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_LINK | 1378c2ecf20Sopenharmony_ci MV88E6XXX_PORT_MAC_CTL_LINK_UP); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci switch (link) { 1408c2ecf20Sopenharmony_ci case LINK_FORCED_DOWN: 1418c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK; 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci case LINK_FORCED_UP: 1448c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK | 1458c2ecf20Sopenharmony_ci MV88E6XXX_PORT_MAC_CTL_LINK_UP; 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci case LINK_UNFORCED: 1488c2ecf20Sopenharmony_ci /* normal link detection */ 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci default: 1518c2ecf20Sopenharmony_ci return -EINVAL; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg); 1558c2ecf20Sopenharmony_ci if (err) 1568c2ecf20Sopenharmony_ci return err; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "p%d: %s link %s\n", port, 1598c2ecf20Sopenharmony_ci reg & MV88E6XXX_PORT_MAC_CTL_FORCE_LINK ? "Force" : "Unforce", 1608c2ecf20Sopenharmony_ci reg & MV88E6XXX_PORT_MAC_CTL_LINK_UP ? "up" : "down"); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip, 1668c2ecf20Sopenharmony_ci int port, int speed, bool alt_bit, 1678c2ecf20Sopenharmony_ci bool force_bit, int duplex) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci u16 reg, ctrl; 1708c2ecf20Sopenharmony_ci int err; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci switch (speed) { 1738c2ecf20Sopenharmony_ci case 10: 1748c2ecf20Sopenharmony_ci ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10; 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci case 100: 1778c2ecf20Sopenharmony_ci ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100; 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci case 200: 1808c2ecf20Sopenharmony_ci if (alt_bit) 1818c2ecf20Sopenharmony_ci ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 | 1828c2ecf20Sopenharmony_ci MV88E6390_PORT_MAC_CTL_ALTSPEED; 1838c2ecf20Sopenharmony_ci else 1848c2ecf20Sopenharmony_ci ctrl = MV88E6065_PORT_MAC_CTL_SPEED_200; 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci case 1000: 1878c2ecf20Sopenharmony_ci ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000; 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci case 2500: 1908c2ecf20Sopenharmony_ci if (alt_bit) 1918c2ecf20Sopenharmony_ci ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 | 1928c2ecf20Sopenharmony_ci MV88E6390_PORT_MAC_CTL_ALTSPEED; 1938c2ecf20Sopenharmony_ci else 1948c2ecf20Sopenharmony_ci ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000; 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci case 10000: 1978c2ecf20Sopenharmony_ci /* all bits set, fall through... */ 1988c2ecf20Sopenharmony_ci case SPEED_UNFORCED: 1998c2ecf20Sopenharmony_ci ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED; 2008c2ecf20Sopenharmony_ci break; 2018c2ecf20Sopenharmony_ci default: 2028c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci switch (duplex) { 2068c2ecf20Sopenharmony_ci case DUPLEX_HALF: 2078c2ecf20Sopenharmony_ci ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX; 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci case DUPLEX_FULL: 2108c2ecf20Sopenharmony_ci ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX | 2118c2ecf20Sopenharmony_ci MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL; 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci case DUPLEX_UNFORCED: 2148c2ecf20Sopenharmony_ci /* normal duplex detection */ 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci default: 2178c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); 2218c2ecf20Sopenharmony_ci if (err) 2228c2ecf20Sopenharmony_ci return err; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK | 2258c2ecf20Sopenharmony_ci MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX | 2268c2ecf20Sopenharmony_ci MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (alt_bit) 2298c2ecf20Sopenharmony_ci reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED; 2308c2ecf20Sopenharmony_ci if (force_bit) { 2318c2ecf20Sopenharmony_ci reg &= ~MV88E6390_PORT_MAC_CTL_FORCE_SPEED; 2328c2ecf20Sopenharmony_ci if (speed != SPEED_UNFORCED) 2338c2ecf20Sopenharmony_ci ctrl |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci reg |= ctrl; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg); 2388c2ecf20Sopenharmony_ci if (err) 2398c2ecf20Sopenharmony_ci return err; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (speed) 2428c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed); 2438c2ecf20Sopenharmony_ci else 2448c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "p%d: Speed unforced\n", port); 2458c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "p%d: %s %s duplex\n", port, 2468c2ecf20Sopenharmony_ci reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce", 2478c2ecf20Sopenharmony_ci reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half"); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci return 0; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/* Support 10, 100, 200 Mbps (e.g. 88E6065 family) */ 2538c2ecf20Sopenharmony_ciint mv88e6065_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, 2548c2ecf20Sopenharmony_ci int speed, int duplex) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci if (speed == SPEED_MAX) 2578c2ecf20Sopenharmony_ci speed = 200; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (speed > 200) 2608c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* Setting 200 Mbps on port 0 to 3 selects 100 Mbps */ 2638c2ecf20Sopenharmony_ci return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false, 2648c2ecf20Sopenharmony_ci duplex); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */ 2688c2ecf20Sopenharmony_ciint mv88e6185_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, 2698c2ecf20Sopenharmony_ci int speed, int duplex) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci if (speed == SPEED_MAX) 2728c2ecf20Sopenharmony_ci speed = 1000; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (speed == 200 || speed > 1000) 2758c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false, 2788c2ecf20Sopenharmony_ci duplex); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci/* Support 10, 100 Mbps (e.g. 88E6250 family) */ 2828c2ecf20Sopenharmony_ciint mv88e6250_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, 2838c2ecf20Sopenharmony_ci int speed, int duplex) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci if (speed == SPEED_MAX) 2868c2ecf20Sopenharmony_ci speed = 100; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (speed > 100) 2898c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false, 2928c2ecf20Sopenharmony_ci duplex); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6341) */ 2968c2ecf20Sopenharmony_ciint mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, 2978c2ecf20Sopenharmony_ci int speed, int duplex) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci if (speed == SPEED_MAX) 3008c2ecf20Sopenharmony_ci speed = port < 5 ? 1000 : 2500; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (speed > 2500) 3038c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (speed == 200 && port != 0) 3068c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (speed == 2500 && port < 5) 3098c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return mv88e6xxx_port_set_speed_duplex(chip, port, speed, !port, true, 3128c2ecf20Sopenharmony_ci duplex); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ciphy_interface_t mv88e6341_port_max_speed_mode(int port) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci if (port == 5) 3188c2ecf20Sopenharmony_ci return PHY_INTERFACE_MODE_2500BASEX; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return PHY_INTERFACE_MODE_NA; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci/* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */ 3248c2ecf20Sopenharmony_ciint mv88e6352_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, 3258c2ecf20Sopenharmony_ci int speed, int duplex) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci if (speed == SPEED_MAX) 3288c2ecf20Sopenharmony_ci speed = 1000; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (speed > 1000) 3318c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (speed == 200 && port < 5) 3348c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, false, 3378c2ecf20Sopenharmony_ci duplex); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */ 3418c2ecf20Sopenharmony_ciint mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, 3428c2ecf20Sopenharmony_ci int speed, int duplex) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci if (speed == SPEED_MAX) 3458c2ecf20Sopenharmony_ci speed = port < 9 ? 1000 : 2500; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (speed > 2500) 3488c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (speed == 200 && port != 0) 3518c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (speed == 2500 && port < 9) 3548c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true, 3578c2ecf20Sopenharmony_ci duplex); 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ciphy_interface_t mv88e6390_port_max_speed_mode(int port) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci if (port == 9 || port == 10) 3638c2ecf20Sopenharmony_ci return PHY_INTERFACE_MODE_2500BASEX; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return PHY_INTERFACE_MODE_NA; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci/* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */ 3698c2ecf20Sopenharmony_ciint mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, 3708c2ecf20Sopenharmony_ci int speed, int duplex) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci if (speed == SPEED_MAX) 3738c2ecf20Sopenharmony_ci speed = port < 9 ? 1000 : 10000; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (speed == 200 && port != 0) 3768c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (speed >= 2500 && port < 9) 3798c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true, 3828c2ecf20Sopenharmony_ci duplex); 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ciphy_interface_t mv88e6390x_port_max_speed_mode(int port) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci if (port == 9 || port == 10) 3888c2ecf20Sopenharmony_ci return PHY_INTERFACE_MODE_XAUI; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci return PHY_INTERFACE_MODE_NA; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port, 3948c2ecf20Sopenharmony_ci phy_interface_t mode, bool force) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci u8 lane; 3978c2ecf20Sopenharmony_ci u16 cmode; 3988c2ecf20Sopenharmony_ci u16 reg; 3998c2ecf20Sopenharmony_ci int err; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Default to a slow mode, so freeing up SERDES interfaces for 4028c2ecf20Sopenharmony_ci * other ports which might use them for SFPs. 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ci if (mode == PHY_INTERFACE_MODE_NA) 4058c2ecf20Sopenharmony_ci mode = PHY_INTERFACE_MODE_1000BASEX; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci switch (mode) { 4088c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_1000BASEX: 4098c2ecf20Sopenharmony_ci cmode = MV88E6XXX_PORT_STS_CMODE_1000BASEX; 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_SGMII: 4128c2ecf20Sopenharmony_ci cmode = MV88E6XXX_PORT_STS_CMODE_SGMII; 4138c2ecf20Sopenharmony_ci break; 4148c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_2500BASEX: 4158c2ecf20Sopenharmony_ci cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX; 4168c2ecf20Sopenharmony_ci break; 4178c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_XGMII: 4188c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_XAUI: 4198c2ecf20Sopenharmony_ci cmode = MV88E6XXX_PORT_STS_CMODE_XAUI; 4208c2ecf20Sopenharmony_ci break; 4218c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RXAUI: 4228c2ecf20Sopenharmony_ci cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI; 4238c2ecf20Sopenharmony_ci break; 4248c2ecf20Sopenharmony_ci default: 4258c2ecf20Sopenharmony_ci cmode = 0; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* cmode doesn't change, nothing to do for us unless forced */ 4298c2ecf20Sopenharmony_ci if (cmode == chip->ports[port].cmode && !force) 4308c2ecf20Sopenharmony_ci return 0; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci lane = mv88e6xxx_serdes_get_lane(chip, port); 4338c2ecf20Sopenharmony_ci if (lane) { 4348c2ecf20Sopenharmony_ci if (chip->ports[port].serdes_irq) { 4358c2ecf20Sopenharmony_ci err = mv88e6xxx_serdes_irq_disable(chip, port, lane); 4368c2ecf20Sopenharmony_ci if (err) 4378c2ecf20Sopenharmony_ci return err; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci err = mv88e6xxx_serdes_power_down(chip, port, lane); 4418c2ecf20Sopenharmony_ci if (err) 4428c2ecf20Sopenharmony_ci return err; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci chip->ports[port].cmode = 0; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (cmode) { 4488c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 4498c2ecf20Sopenharmony_ci if (err) 4508c2ecf20Sopenharmony_ci return err; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci reg &= ~MV88E6XXX_PORT_STS_CMODE_MASK; 4538c2ecf20Sopenharmony_ci reg |= cmode; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg); 4568c2ecf20Sopenharmony_ci if (err) 4578c2ecf20Sopenharmony_ci return err; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci chip->ports[port].cmode = cmode; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci lane = mv88e6xxx_serdes_get_lane(chip, port); 4628c2ecf20Sopenharmony_ci if (!lane) 4638c2ecf20Sopenharmony_ci return -ENODEV; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci err = mv88e6xxx_serdes_power_up(chip, port, lane); 4668c2ecf20Sopenharmony_ci if (err) 4678c2ecf20Sopenharmony_ci return err; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (chip->ports[port].serdes_irq) { 4708c2ecf20Sopenharmony_ci err = mv88e6xxx_serdes_irq_enable(chip, port, lane); 4718c2ecf20Sopenharmony_ci if (err) 4728c2ecf20Sopenharmony_ci return err; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return 0; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ciint mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, 4808c2ecf20Sopenharmony_ci phy_interface_t mode) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci if (port != 9 && port != 10) 4838c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return mv88e6xxx_port_set_cmode(chip, port, mode, false); 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ciint mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port, 4898c2ecf20Sopenharmony_ci phy_interface_t mode) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci if (port != 9 && port != 10) 4928c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci switch (mode) { 4958c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_NA: 4968c2ecf20Sopenharmony_ci return 0; 4978c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_XGMII: 4988c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_XAUI: 4998c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RXAUI: 5008c2ecf20Sopenharmony_ci return -EINVAL; 5018c2ecf20Sopenharmony_ci default: 5028c2ecf20Sopenharmony_ci break; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return mv88e6xxx_port_set_cmode(chip, port, mode, false); 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic int mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip *chip, 5098c2ecf20Sopenharmony_ci int port) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci int err, addr; 5128c2ecf20Sopenharmony_ci u16 reg, bits; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci if (port != 5) 5158c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci addr = chip->info->port_base_addr + port; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci err = mv88e6xxx_port_hidden_read(chip, 0x7, addr, 0, ®); 5208c2ecf20Sopenharmony_ci if (err) 5218c2ecf20Sopenharmony_ci return err; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci bits = MV88E6341_PORT_RESERVED_1A_FORCE_CMODE | 5248c2ecf20Sopenharmony_ci MV88E6341_PORT_RESERVED_1A_SGMII_AN; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if ((reg & bits) == bits) 5278c2ecf20Sopenharmony_ci return 0; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci reg |= bits; 5308c2ecf20Sopenharmony_ci return mv88e6xxx_port_hidden_write(chip, 0x7, addr, 0, reg); 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ciint mv88e6341_port_set_cmode(struct mv88e6xxx_chip *chip, int port, 5348c2ecf20Sopenharmony_ci phy_interface_t mode) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci int err; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (port != 5) 5398c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci switch (mode) { 5428c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_NA: 5438c2ecf20Sopenharmony_ci return 0; 5448c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_XGMII: 5458c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_XAUI: 5468c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_RXAUI: 5478c2ecf20Sopenharmony_ci return -EINVAL; 5488c2ecf20Sopenharmony_ci default: 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci err = mv88e6341_port_set_cmode_writable(chip, port); 5538c2ecf20Sopenharmony_ci if (err) 5548c2ecf20Sopenharmony_ci return err; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci return mv88e6xxx_port_set_cmode(chip, port, mode, true); 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ciint mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci int err; 5628c2ecf20Sopenharmony_ci u16 reg; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 5658c2ecf20Sopenharmony_ci if (err) 5668c2ecf20Sopenharmony_ci return err; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci *cmode = reg & MV88E6185_PORT_STS_CMODE_MASK; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci return 0; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ciint mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci int err; 5768c2ecf20Sopenharmony_ci u16 reg; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); 5798c2ecf20Sopenharmony_ci if (err) 5808c2ecf20Sopenharmony_ci return err; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci *cmode = reg & MV88E6XXX_PORT_STS_CMODE_MASK; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return 0; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci/* Offset 0x02: Jamming Control 5888c2ecf20Sopenharmony_ci * 5898c2ecf20Sopenharmony_ci * Do not limit the period of time that this port can be paused for by 5908c2ecf20Sopenharmony_ci * the remote end or the period of time that this port can pause the 5918c2ecf20Sopenharmony_ci * remote end. 5928c2ecf20Sopenharmony_ci */ 5938c2ecf20Sopenharmony_ciint mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, 5948c2ecf20Sopenharmony_ci u8 out) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6097_PORT_JAM_CTL, 5978c2ecf20Sopenharmony_ci out << 8 | in); 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ciint mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, 6018c2ecf20Sopenharmony_ci u8 out) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci int err; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL, 6068c2ecf20Sopenharmony_ci MV88E6390_PORT_FLOW_CTL_UPDATE | 6078c2ecf20Sopenharmony_ci MV88E6390_PORT_FLOW_CTL_LIMIT_IN | in); 6088c2ecf20Sopenharmony_ci if (err) 6098c2ecf20Sopenharmony_ci return err; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL, 6128c2ecf20Sopenharmony_ci MV88E6390_PORT_FLOW_CTL_UPDATE | 6138c2ecf20Sopenharmony_ci MV88E6390_PORT_FLOW_CTL_LIMIT_OUT | out); 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci/* Offset 0x04: Port Control Register */ 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic const char * const mv88e6xxx_port_state_names[] = { 6198c2ecf20Sopenharmony_ci [MV88E6XXX_PORT_CTL0_STATE_DISABLED] = "Disabled", 6208c2ecf20Sopenharmony_ci [MV88E6XXX_PORT_CTL0_STATE_BLOCKING] = "Blocking/Listening", 6218c2ecf20Sopenharmony_ci [MV88E6XXX_PORT_CTL0_STATE_LEARNING] = "Learning", 6228c2ecf20Sopenharmony_ci [MV88E6XXX_PORT_CTL0_STATE_FORWARDING] = "Forwarding", 6238c2ecf20Sopenharmony_ci}; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ciint mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci u16 reg; 6288c2ecf20Sopenharmony_ci int err; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 6318c2ecf20Sopenharmony_ci if (err) 6328c2ecf20Sopenharmony_ci return err; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci reg &= ~MV88E6XXX_PORT_CTL0_STATE_MASK; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci switch (state) { 6378c2ecf20Sopenharmony_ci case BR_STATE_DISABLED: 6388c2ecf20Sopenharmony_ci state = MV88E6XXX_PORT_CTL0_STATE_DISABLED; 6398c2ecf20Sopenharmony_ci break; 6408c2ecf20Sopenharmony_ci case BR_STATE_BLOCKING: 6418c2ecf20Sopenharmony_ci case BR_STATE_LISTENING: 6428c2ecf20Sopenharmony_ci state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING; 6438c2ecf20Sopenharmony_ci break; 6448c2ecf20Sopenharmony_ci case BR_STATE_LEARNING: 6458c2ecf20Sopenharmony_ci state = MV88E6XXX_PORT_CTL0_STATE_LEARNING; 6468c2ecf20Sopenharmony_ci break; 6478c2ecf20Sopenharmony_ci case BR_STATE_FORWARDING: 6488c2ecf20Sopenharmony_ci state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING; 6498c2ecf20Sopenharmony_ci break; 6508c2ecf20Sopenharmony_ci default: 6518c2ecf20Sopenharmony_ci return -EINVAL; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci reg |= state; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 6578c2ecf20Sopenharmony_ci if (err) 6588c2ecf20Sopenharmony_ci return err; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "p%d: PortState set to %s\n", port, 6618c2ecf20Sopenharmony_ci mv88e6xxx_port_state_names[state]); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci return 0; 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ciint mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port, 6678c2ecf20Sopenharmony_ci enum mv88e6xxx_egress_mode mode) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci int err; 6708c2ecf20Sopenharmony_ci u16 reg; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 6738c2ecf20Sopenharmony_ci if (err) 6748c2ecf20Sopenharmony_ci return err; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci reg &= ~MV88E6XXX_PORT_CTL0_EGRESS_MODE_MASK; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci switch (mode) { 6798c2ecf20Sopenharmony_ci case MV88E6XXX_EGRESS_MODE_UNMODIFIED: 6808c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNMODIFIED; 6818c2ecf20Sopenharmony_ci break; 6828c2ecf20Sopenharmony_ci case MV88E6XXX_EGRESS_MODE_UNTAGGED: 6838c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNTAGGED; 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci case MV88E6XXX_EGRESS_MODE_TAGGED: 6868c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_TAGGED; 6878c2ecf20Sopenharmony_ci break; 6888c2ecf20Sopenharmony_ci case MV88E6XXX_EGRESS_MODE_ETHERTYPE: 6898c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_ETHER_TYPE_DSA; 6908c2ecf20Sopenharmony_ci break; 6918c2ecf20Sopenharmony_ci default: 6928c2ecf20Sopenharmony_ci return -EINVAL; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ciint mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, 6998c2ecf20Sopenharmony_ci enum mv88e6xxx_frame_mode mode) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci int err; 7028c2ecf20Sopenharmony_ci u16 reg; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 7058c2ecf20Sopenharmony_ci if (err) 7068c2ecf20Sopenharmony_ci return err; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci switch (mode) { 7118c2ecf20Sopenharmony_ci case MV88E6XXX_FRAME_MODE_NORMAL: 7128c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL; 7138c2ecf20Sopenharmony_ci break; 7148c2ecf20Sopenharmony_ci case MV88E6XXX_FRAME_MODE_DSA: 7158c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA; 7168c2ecf20Sopenharmony_ci break; 7178c2ecf20Sopenharmony_ci default: 7188c2ecf20Sopenharmony_ci return -EINVAL; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ciint mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, 7258c2ecf20Sopenharmony_ci enum mv88e6xxx_frame_mode mode) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci int err; 7288c2ecf20Sopenharmony_ci u16 reg; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 7318c2ecf20Sopenharmony_ci if (err) 7328c2ecf20Sopenharmony_ci return err; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci switch (mode) { 7378c2ecf20Sopenharmony_ci case MV88E6XXX_FRAME_MODE_NORMAL: 7388c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL; 7398c2ecf20Sopenharmony_ci break; 7408c2ecf20Sopenharmony_ci case MV88E6XXX_FRAME_MODE_DSA: 7418c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA; 7428c2ecf20Sopenharmony_ci break; 7438c2ecf20Sopenharmony_ci case MV88E6XXX_FRAME_MODE_PROVIDER: 7448c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_PROVIDER; 7458c2ecf20Sopenharmony_ci break; 7468c2ecf20Sopenharmony_ci case MV88E6XXX_FRAME_MODE_ETHERTYPE: 7478c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_ETHER_TYPE_DSA; 7488c2ecf20Sopenharmony_ci break; 7498c2ecf20Sopenharmony_ci default: 7508c2ecf20Sopenharmony_ci return -EINVAL; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip, 7578c2ecf20Sopenharmony_ci int port, bool unicast) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci int err; 7608c2ecf20Sopenharmony_ci u16 reg; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 7638c2ecf20Sopenharmony_ci if (err) 7648c2ecf20Sopenharmony_ci return err; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (unicast) 7678c2ecf20Sopenharmony_ci reg |= MV88E6185_PORT_CTL0_FORWARD_UNKNOWN; 7688c2ecf20Sopenharmony_ci else 7698c2ecf20Sopenharmony_ci reg &= ~MV88E6185_PORT_CTL0_FORWARD_UNKNOWN; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ciint mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, 7758c2ecf20Sopenharmony_ci bool unicast, bool multicast) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci int err; 7788c2ecf20Sopenharmony_ci u16 reg; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); 7818c2ecf20Sopenharmony_ci if (err) 7828c2ecf20Sopenharmony_ci return err; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_MASK; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (unicast && multicast) 7878c2ecf20Sopenharmony_ci reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_ALL_UNKNOWN_DA; 7888c2ecf20Sopenharmony_ci else if (unicast) 7898c2ecf20Sopenharmony_ci reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_MC_DA; 7908c2ecf20Sopenharmony_ci else if (multicast) 7918c2ecf20Sopenharmony_ci reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_UC_DA; 7928c2ecf20Sopenharmony_ci else 7938c2ecf20Sopenharmony_ci reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_DA; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci/* Offset 0x05: Port Control 1 */ 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ciint mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port, 8018c2ecf20Sopenharmony_ci bool message_port) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci u16 val; 8048c2ecf20Sopenharmony_ci int err; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val); 8078c2ecf20Sopenharmony_ci if (err) 8088c2ecf20Sopenharmony_ci return err; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (message_port) 8118c2ecf20Sopenharmony_ci val |= MV88E6XXX_PORT_CTL1_MESSAGE_PORT; 8128c2ecf20Sopenharmony_ci else 8138c2ecf20Sopenharmony_ci val &= ~MV88E6XXX_PORT_CTL1_MESSAGE_PORT; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val); 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci/* Offset 0x06: Port Based VLAN Map */ 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ciint mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci const u16 mask = mv88e6xxx_port_mask(chip); 8238c2ecf20Sopenharmony_ci u16 reg; 8248c2ecf20Sopenharmony_ci int err; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®); 8278c2ecf20Sopenharmony_ci if (err) 8288c2ecf20Sopenharmony_ci return err; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci reg &= ~mask; 8318c2ecf20Sopenharmony_ci reg |= map & mask; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg); 8348c2ecf20Sopenharmony_ci if (err) 8358c2ecf20Sopenharmony_ci return err; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "p%d: VLANTable set to %.3x\n", port, map); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci return 0; 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ciint mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4; 8458c2ecf20Sopenharmony_ci u16 reg; 8468c2ecf20Sopenharmony_ci int err; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */ 8498c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®); 8508c2ecf20Sopenharmony_ci if (err) 8518c2ecf20Sopenharmony_ci return err; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci *fid = (reg & 0xf000) >> 12; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* Port's default FID upper bits are located in reg 0x05, offset 0 */ 8568c2ecf20Sopenharmony_ci if (upper_mask) { 8578c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, 8588c2ecf20Sopenharmony_ci ®); 8598c2ecf20Sopenharmony_ci if (err) 8608c2ecf20Sopenharmony_ci return err; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci *fid |= (reg & upper_mask) << 4; 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci return 0; 8668c2ecf20Sopenharmony_ci} 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ciint mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4; 8718c2ecf20Sopenharmony_ci u16 reg; 8728c2ecf20Sopenharmony_ci int err; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci if (fid >= mv88e6xxx_num_databases(chip)) 8758c2ecf20Sopenharmony_ci return -EINVAL; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */ 8788c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, ®); 8798c2ecf20Sopenharmony_ci if (err) 8808c2ecf20Sopenharmony_ci return err; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci reg &= 0x0fff; 8838c2ecf20Sopenharmony_ci reg |= (fid & 0x000f) << 12; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg); 8868c2ecf20Sopenharmony_ci if (err) 8878c2ecf20Sopenharmony_ci return err; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci /* Port's default FID upper bits are located in reg 0x05, offset 0 */ 8908c2ecf20Sopenharmony_ci if (upper_mask) { 8918c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, 8928c2ecf20Sopenharmony_ci ®); 8938c2ecf20Sopenharmony_ci if (err) 8948c2ecf20Sopenharmony_ci return err; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci reg &= ~upper_mask; 8978c2ecf20Sopenharmony_ci reg |= (fid >> 4) & upper_mask; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, 9008c2ecf20Sopenharmony_ci reg); 9018c2ecf20Sopenharmony_ci if (err) 9028c2ecf20Sopenharmony_ci return err; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "p%d: FID set to %u\n", port, fid); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci return 0; 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci/* Offset 0x07: Default Port VLAN ID & Priority */ 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ciint mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci u16 reg; 9158c2ecf20Sopenharmony_ci int err; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 9188c2ecf20Sopenharmony_ci ®); 9198c2ecf20Sopenharmony_ci if (err) 9208c2ecf20Sopenharmony_ci return err; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci *pvid = reg & MV88E6XXX_PORT_DEFAULT_VLAN_MASK; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci return 0; 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ciint mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid) 9288c2ecf20Sopenharmony_ci{ 9298c2ecf20Sopenharmony_ci u16 reg; 9308c2ecf20Sopenharmony_ci int err; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 9338c2ecf20Sopenharmony_ci ®); 9348c2ecf20Sopenharmony_ci if (err) 9358c2ecf20Sopenharmony_ci return err; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci reg &= ~MV88E6XXX_PORT_DEFAULT_VLAN_MASK; 9388c2ecf20Sopenharmony_ci reg |= pvid & MV88E6XXX_PORT_DEFAULT_VLAN_MASK; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN, 9418c2ecf20Sopenharmony_ci reg); 9428c2ecf20Sopenharmony_ci if (err) 9438c2ecf20Sopenharmony_ci return err; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "p%d: DefaultVID set to %u\n", port, pvid); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return 0; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci/* Offset 0x08: Port Control 2 Register */ 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_cistatic const char * const mv88e6xxx_port_8021q_mode_names[] = { 9538c2ecf20Sopenharmony_ci [MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED] = "Disabled", 9548c2ecf20Sopenharmony_ci [MV88E6XXX_PORT_CTL2_8021Q_MODE_FALLBACK] = "Fallback", 9558c2ecf20Sopenharmony_ci [MV88E6XXX_PORT_CTL2_8021Q_MODE_CHECK] = "Check", 9568c2ecf20Sopenharmony_ci [MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE] = "Secure", 9578c2ecf20Sopenharmony_ci}; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip, 9608c2ecf20Sopenharmony_ci int port, bool multicast) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci int err; 9638c2ecf20Sopenharmony_ci u16 reg; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 9668c2ecf20Sopenharmony_ci if (err) 9678c2ecf20Sopenharmony_ci return err; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci if (multicast) 9708c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD; 9718c2ecf20Sopenharmony_ci else 9728c2ecf20Sopenharmony_ci reg &= ~MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 9758c2ecf20Sopenharmony_ci} 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ciint mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, 9788c2ecf20Sopenharmony_ci bool unicast, bool multicast) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci int err; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci err = mv88e6185_port_set_forward_unknown(chip, port, unicast); 9838c2ecf20Sopenharmony_ci if (err) 9848c2ecf20Sopenharmony_ci return err; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci return mv88e6185_port_set_default_forward(chip, port, multicast); 9878c2ecf20Sopenharmony_ci} 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ciint mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port, 9908c2ecf20Sopenharmony_ci int upstream_port) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci int err; 9938c2ecf20Sopenharmony_ci u16 reg; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 9968c2ecf20Sopenharmony_ci if (err) 9978c2ecf20Sopenharmony_ci return err; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci reg &= ~MV88E6095_PORT_CTL2_CPU_PORT_MASK; 10008c2ecf20Sopenharmony_ci reg |= upstream_port; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ciint mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port, 10068c2ecf20Sopenharmony_ci enum mv88e6xxx_egress_direction direction, 10078c2ecf20Sopenharmony_ci bool mirror) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci bool *mirror_port; 10108c2ecf20Sopenharmony_ci u16 reg; 10118c2ecf20Sopenharmony_ci u16 bit; 10128c2ecf20Sopenharmony_ci int err; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 10158c2ecf20Sopenharmony_ci if (err) 10168c2ecf20Sopenharmony_ci return err; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci switch (direction) { 10198c2ecf20Sopenharmony_ci case MV88E6XXX_EGRESS_DIR_INGRESS: 10208c2ecf20Sopenharmony_ci bit = MV88E6XXX_PORT_CTL2_INGRESS_MONITOR; 10218c2ecf20Sopenharmony_ci mirror_port = &chip->ports[port].mirror_ingress; 10228c2ecf20Sopenharmony_ci break; 10238c2ecf20Sopenharmony_ci case MV88E6XXX_EGRESS_DIR_EGRESS: 10248c2ecf20Sopenharmony_ci bit = MV88E6XXX_PORT_CTL2_EGRESS_MONITOR; 10258c2ecf20Sopenharmony_ci mirror_port = &chip->ports[port].mirror_egress; 10268c2ecf20Sopenharmony_ci break; 10278c2ecf20Sopenharmony_ci default: 10288c2ecf20Sopenharmony_ci return -EINVAL; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci reg &= ~bit; 10328c2ecf20Sopenharmony_ci if (mirror) 10338c2ecf20Sopenharmony_ci reg |= bit; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 10368c2ecf20Sopenharmony_ci if (!err) 10378c2ecf20Sopenharmony_ci *mirror_port = mirror; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci return err; 10408c2ecf20Sopenharmony_ci} 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ciint mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port, 10438c2ecf20Sopenharmony_ci u16 mode) 10448c2ecf20Sopenharmony_ci{ 10458c2ecf20Sopenharmony_ci u16 reg; 10468c2ecf20Sopenharmony_ci int err; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 10498c2ecf20Sopenharmony_ci if (err) 10508c2ecf20Sopenharmony_ci return err; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci reg &= ~MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK; 10538c2ecf20Sopenharmony_ci reg |= mode & MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 10568c2ecf20Sopenharmony_ci if (err) 10578c2ecf20Sopenharmony_ci return err; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "p%d: 802.1QMode set to %s\n", port, 10608c2ecf20Sopenharmony_ci mv88e6xxx_port_8021q_mode_names[mode]); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci return 0; 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ciint mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci u16 reg; 10688c2ecf20Sopenharmony_ci int err; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 10718c2ecf20Sopenharmony_ci if (err) 10728c2ecf20Sopenharmony_ci return err; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL2_MAP_DA; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 10778c2ecf20Sopenharmony_ci} 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ciint mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port, 10808c2ecf20Sopenharmony_ci size_t size) 10818c2ecf20Sopenharmony_ci{ 10828c2ecf20Sopenharmony_ci u16 reg; 10838c2ecf20Sopenharmony_ci int err; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci size += VLAN_ETH_HLEN + ETH_FCS_LEN; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); 10888c2ecf20Sopenharmony_ci if (err) 10898c2ecf20Sopenharmony_ci return err; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci reg &= ~MV88E6XXX_PORT_CTL2_JUMBO_MODE_MASK; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (size <= 1522) 10948c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_1522; 10958c2ecf20Sopenharmony_ci else if (size <= 2048) 10968c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_2048; 10978c2ecf20Sopenharmony_ci else if (size <= 10240) 10988c2ecf20Sopenharmony_ci reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_10240; 10998c2ecf20Sopenharmony_ci else 11008c2ecf20Sopenharmony_ci return -ERANGE; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); 11038c2ecf20Sopenharmony_ci} 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci/* Offset 0x09: Port Rate Control */ 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ciint mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1, 11108c2ecf20Sopenharmony_ci 0x0000); 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ciint mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port) 11148c2ecf20Sopenharmony_ci{ 11158c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1, 11168c2ecf20Sopenharmony_ci 0x0001); 11178c2ecf20Sopenharmony_ci} 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci/* Offset 0x0C: Port ATU Control */ 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ciint mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ATU_CTL, 0); 11248c2ecf20Sopenharmony_ci} 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci/* Offset 0x0D: (Priority) Override Register */ 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ciint mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0); 11318c2ecf20Sopenharmony_ci} 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci/* Offset 0x0f: Port Ether type */ 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ciint mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port, 11368c2ecf20Sopenharmony_ci u16 etype) 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype); 11398c2ecf20Sopenharmony_ci} 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci/* Offset 0x18: Port IEEE Priority Remapping Registers [0-3] 11428c2ecf20Sopenharmony_ci * Offset 0x19: Port IEEE Priority Remapping Registers [4-7] 11438c2ecf20Sopenharmony_ci */ 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ciint mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci int err; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci /* Use a direct priority mapping for all IEEE tagged frames */ 11508c2ecf20Sopenharmony_ci err = mv88e6xxx_port_write(chip, port, 11518c2ecf20Sopenharmony_ci MV88E6095_PORT_IEEE_PRIO_REMAP_0123, 11528c2ecf20Sopenharmony_ci 0x3210); 11538c2ecf20Sopenharmony_ci if (err) 11548c2ecf20Sopenharmony_ci return err; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, 11578c2ecf20Sopenharmony_ci MV88E6095_PORT_IEEE_PRIO_REMAP_4567, 11588c2ecf20Sopenharmony_ci 0x7654); 11598c2ecf20Sopenharmony_ci} 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_cistatic int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip, 11628c2ecf20Sopenharmony_ci int port, u16 table, u8 ptr, u16 data) 11638c2ecf20Sopenharmony_ci{ 11648c2ecf20Sopenharmony_ci u16 reg; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci reg = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE | table | 11678c2ecf20Sopenharmony_ci (ptr << __bf_shf(MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_PTR_MASK)) | 11688c2ecf20Sopenharmony_ci (data & MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_DATA_MASK); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, 11718c2ecf20Sopenharmony_ci MV88E6390_PORT_IEEE_PRIO_MAP_TABLE, reg); 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ciint mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci int err, i; 11778c2ecf20Sopenharmony_ci u16 table; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci for (i = 0; i <= 7; i++) { 11808c2ecf20Sopenharmony_ci table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP; 11818c2ecf20Sopenharmony_ci err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, 11828c2ecf20Sopenharmony_ci (i | i << 4)); 11838c2ecf20Sopenharmony_ci if (err) 11848c2ecf20Sopenharmony_ci return err; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP; 11878c2ecf20Sopenharmony_ci err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); 11888c2ecf20Sopenharmony_ci if (err) 11898c2ecf20Sopenharmony_ci return err; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP; 11928c2ecf20Sopenharmony_ci err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); 11938c2ecf20Sopenharmony_ci if (err) 11948c2ecf20Sopenharmony_ci return err; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP; 11978c2ecf20Sopenharmony_ci err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); 11988c2ecf20Sopenharmony_ci if (err) 11998c2ecf20Sopenharmony_ci return err; 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci return 0; 12038c2ecf20Sopenharmony_ci} 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci/* Offset 0x0E: Policy Control Register */ 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ciint mv88e6352_port_set_policy(struct mv88e6xxx_chip *chip, int port, 12088c2ecf20Sopenharmony_ci enum mv88e6xxx_policy_mapping mapping, 12098c2ecf20Sopenharmony_ci enum mv88e6xxx_policy_action action) 12108c2ecf20Sopenharmony_ci{ 12118c2ecf20Sopenharmony_ci u16 reg, mask, val; 12128c2ecf20Sopenharmony_ci int shift; 12138c2ecf20Sopenharmony_ci int err; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci switch (mapping) { 12168c2ecf20Sopenharmony_ci case MV88E6XXX_POLICY_MAPPING_DA: 12178c2ecf20Sopenharmony_ci shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_DA_MASK); 12188c2ecf20Sopenharmony_ci mask = MV88E6XXX_PORT_POLICY_CTL_DA_MASK; 12198c2ecf20Sopenharmony_ci break; 12208c2ecf20Sopenharmony_ci case MV88E6XXX_POLICY_MAPPING_SA: 12218c2ecf20Sopenharmony_ci shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_SA_MASK); 12228c2ecf20Sopenharmony_ci mask = MV88E6XXX_PORT_POLICY_CTL_SA_MASK; 12238c2ecf20Sopenharmony_ci break; 12248c2ecf20Sopenharmony_ci case MV88E6XXX_POLICY_MAPPING_VTU: 12258c2ecf20Sopenharmony_ci shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VTU_MASK); 12268c2ecf20Sopenharmony_ci mask = MV88E6XXX_PORT_POLICY_CTL_VTU_MASK; 12278c2ecf20Sopenharmony_ci break; 12288c2ecf20Sopenharmony_ci case MV88E6XXX_POLICY_MAPPING_ETYPE: 12298c2ecf20Sopenharmony_ci shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK); 12308c2ecf20Sopenharmony_ci mask = MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK; 12318c2ecf20Sopenharmony_ci break; 12328c2ecf20Sopenharmony_ci case MV88E6XXX_POLICY_MAPPING_PPPOE: 12338c2ecf20Sopenharmony_ci shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK); 12348c2ecf20Sopenharmony_ci mask = MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK; 12358c2ecf20Sopenharmony_ci break; 12368c2ecf20Sopenharmony_ci case MV88E6XXX_POLICY_MAPPING_VBAS: 12378c2ecf20Sopenharmony_ci shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK); 12388c2ecf20Sopenharmony_ci mask = MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK; 12398c2ecf20Sopenharmony_ci break; 12408c2ecf20Sopenharmony_ci case MV88E6XXX_POLICY_MAPPING_OPT82: 12418c2ecf20Sopenharmony_ci shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK); 12428c2ecf20Sopenharmony_ci mask = MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK; 12438c2ecf20Sopenharmony_ci break; 12448c2ecf20Sopenharmony_ci case MV88E6XXX_POLICY_MAPPING_UDP: 12458c2ecf20Sopenharmony_ci shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_UDP_MASK); 12468c2ecf20Sopenharmony_ci mask = MV88E6XXX_PORT_POLICY_CTL_UDP_MASK; 12478c2ecf20Sopenharmony_ci break; 12488c2ecf20Sopenharmony_ci default: 12498c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci switch (action) { 12538c2ecf20Sopenharmony_ci case MV88E6XXX_POLICY_ACTION_NORMAL: 12548c2ecf20Sopenharmony_ci val = MV88E6XXX_PORT_POLICY_CTL_NORMAL; 12558c2ecf20Sopenharmony_ci break; 12568c2ecf20Sopenharmony_ci case MV88E6XXX_POLICY_ACTION_MIRROR: 12578c2ecf20Sopenharmony_ci val = MV88E6XXX_PORT_POLICY_CTL_MIRROR; 12588c2ecf20Sopenharmony_ci break; 12598c2ecf20Sopenharmony_ci case MV88E6XXX_POLICY_ACTION_TRAP: 12608c2ecf20Sopenharmony_ci val = MV88E6XXX_PORT_POLICY_CTL_TRAP; 12618c2ecf20Sopenharmony_ci break; 12628c2ecf20Sopenharmony_ci case MV88E6XXX_POLICY_ACTION_DISCARD: 12638c2ecf20Sopenharmony_ci val = MV88E6XXX_PORT_POLICY_CTL_DISCARD; 12648c2ecf20Sopenharmony_ci break; 12658c2ecf20Sopenharmony_ci default: 12668c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_POLICY_CTL, ®); 12708c2ecf20Sopenharmony_ci if (err) 12718c2ecf20Sopenharmony_ci return err; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci reg &= ~mask; 12748c2ecf20Sopenharmony_ci reg |= (val << shift) & mask; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_POLICY_CTL, reg); 12778c2ecf20Sopenharmony_ci} 1278