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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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					  &reg);
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, &reg);
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					  &reg);
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				  &reg);
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				  &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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