brintos

brintos / linux-shallow public Read only

0
0
Text · 40.0 KiB · 04053fd Raw
1727 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Marvell 88E6xxx Switch Port Registers support4 *5 * Copyright (c) 2008 Marvell Semiconductor6 *7 * Copyright (c) 2016-2017 Savoir-faire Linux Inc.8 *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>9 */10 11#include <linux/bitfield.h>12#include <linux/if_bridge.h>13#include <linux/phy.h>14#include <linux/phylink.h>15 16#include "chip.h"17#include "global2.h"18#include "port.h"19#include "serdes.h"20 21int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,22			u16 *val)23{24	int addr = chip->info->port_base_addr + port;25 26	return mv88e6xxx_read(chip, addr, reg, val);27}28 29int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,30			    int bit, int val)31{32	int addr = chip->info->port_base_addr + port;33 34	return mv88e6xxx_wait_bit(chip, addr, reg, bit, val);35}36 37int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,38			 u16 val)39{40	int addr = chip->info->port_base_addr + port;41 42	return mv88e6xxx_write(chip, addr, reg, val);43}44 45/* Offset 0x00: MAC (or PCS or Physical) Status Register46 *47 * For most devices, this is read only. However the 6185 has the MyPause48 * bit read/write.49 */50int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,51			     int pause)52{53	u16 reg;54	int err;55 56	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);57	if (err)58		return err;59 60	if (pause)61		reg |= MV88E6XXX_PORT_STS_MY_PAUSE;62	else63		reg &= ~MV88E6XXX_PORT_STS_MY_PAUSE;64 65	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);66}67 68/* Offset 0x01: MAC (or PCS or Physical) Control Register69 *70 * Link, Duplex and Flow Control have one force bit, one value bit.71 *72 * For port's MAC speed, ForceSpd (or SpdValue) bits 1:0 program the value.73 * Alternative values require the 200BASE (or AltSpeed) bit 12 set.74 * Newer chips need a ForcedSpd bit 13 set to consider the value.75 */76 77static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,78					  phy_interface_t mode)79{80	u16 reg;81	int err;82 83	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);84	if (err)85		return err;86 87	reg &= ~(MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |88		 MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK);89 90	switch (mode) {91	case PHY_INTERFACE_MODE_RGMII_RXID:92		reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK;93		break;94	case PHY_INTERFACE_MODE_RGMII_TXID:95		reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;96		break;97	case PHY_INTERFACE_MODE_RGMII_ID:98		reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |99			MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;100		break;101	case PHY_INTERFACE_MODE_RGMII:102		break;103	default:104		return 0;105	}106 107	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);108	if (err)109		return err;110 111	dev_dbg(chip->dev, "p%d: delay RXCLK %s, TXCLK %s\n", port,112		reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK ? "yes" : "no",113		reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK ? "yes" : "no");114 115	return 0;116}117 118int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,119				   phy_interface_t mode)120{121	if (port < 5)122		return -EOPNOTSUPP;123 124	return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);125}126 127int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,128				   phy_interface_t mode)129{130	if (port != 0)131		return -EOPNOTSUPP;132 133	return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);134}135 136int mv88e6320_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,137				   phy_interface_t mode)138{139	if (port != 2 && port != 5 && port != 6)140		return -EOPNOTSUPP;141 142	return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);143}144 145int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link)146{147	u16 reg;148	int err;149 150	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);151	if (err)152		return err;153 154	reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |155		 MV88E6XXX_PORT_MAC_CTL_LINK_UP);156 157	switch (link) {158	case LINK_FORCED_DOWN:159		reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK;160		break;161	case LINK_FORCED_UP:162		reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |163			MV88E6XXX_PORT_MAC_CTL_LINK_UP;164		break;165	case LINK_UNFORCED:166		/* normal link detection */167		break;168	default:169		return -EINVAL;170	}171 172	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);173	if (err)174		return err;175 176	dev_dbg(chip->dev, "p%d: %s link %s\n", port,177		reg & MV88E6XXX_PORT_MAC_CTL_FORCE_LINK ? "Force" : "Unforce",178		reg & MV88E6XXX_PORT_MAC_CTL_LINK_UP ? "up" : "down");179 180	return 0;181}182 183int mv88e6xxx_port_sync_link(struct mv88e6xxx_chip *chip, int port, unsigned int mode, bool isup)184{185	const struct mv88e6xxx_ops *ops = chip->info->ops;186	int err = 0;187	int link;188 189	if (isup)190		link = LINK_FORCED_UP;191	else192		link = LINK_FORCED_DOWN;193 194	if (ops->port_set_link)195		err = ops->port_set_link(chip, port, link);196 197	return err;198}199 200int mv88e6185_port_sync_link(struct mv88e6xxx_chip *chip, int port, unsigned int mode, bool isup)201{202	const struct mv88e6xxx_ops *ops = chip->info->ops;203	int err = 0;204	int link;205 206	if (mode == MLO_AN_INBAND)207		link = LINK_UNFORCED;208	else if (isup)209		link = LINK_FORCED_UP;210	else211		link = LINK_FORCED_DOWN;212 213	if (ops->port_set_link)214		err = ops->port_set_link(chip, port, link);215 216	return err;217}218 219static int mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip,220					   int port, int speed, bool alt_bit,221					   bool force_bit, int duplex)222{223	u16 reg, ctrl;224	int err;225 226	switch (speed) {227	case 10:228		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;229		break;230	case 100:231		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;232		break;233	case 200:234		if (alt_bit)235			ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |236				MV88E6390_PORT_MAC_CTL_ALTSPEED;237		else238			ctrl = MV88E6065_PORT_MAC_CTL_SPEED_200;239		break;240	case 1000:241		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;242		break;243	case 2500:244		if (alt_bit)245			ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |246				MV88E6390_PORT_MAC_CTL_ALTSPEED;247		else248			ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000;249		break;250	case 10000:251		/* all bits set, fall through... */252	case SPEED_UNFORCED:253		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;254		break;255	default:256		return -EOPNOTSUPP;257	}258 259	switch (duplex) {260	case DUPLEX_HALF:261		ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;262		break;263	case DUPLEX_FULL:264		ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |265			MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;266		break;267	case DUPLEX_UNFORCED:268		/* normal duplex detection */269		break;270	default:271		return -EOPNOTSUPP;272	}273 274	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);275	if (err)276		return err;277 278	reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |279		 MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |280		 MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);281 282	if (alt_bit)283		reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED;284	if (force_bit) {285		reg &= ~MV88E6390_PORT_MAC_CTL_FORCE_SPEED;286		if (speed != SPEED_UNFORCED)287			ctrl |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;288	}289	reg |= ctrl;290 291	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);292	if (err)293		return err;294 295	if (speed != SPEED_UNFORCED)296		dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);297	else298		dev_dbg(chip->dev, "p%d: Speed unforced\n", port);299	dev_dbg(chip->dev, "p%d: %s %s duplex\n", port,300		reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce",301		reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half");302 303	return 0;304}305 306/* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */307int mv88e6185_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,308				    int speed, int duplex)309{310	if (speed == 200 || speed > 1000)311		return -EOPNOTSUPP;312 313	return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false,314					       duplex);315}316 317/* Support 10, 100 Mbps (e.g. 88E6250 family) */318int mv88e6250_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,319				    int speed, int duplex)320{321	if (speed > 100)322		return -EOPNOTSUPP;323 324	return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false,325					       duplex);326}327 328/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6341) */329int mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,330				    int speed, int duplex)331{332	if (speed > 2500)333		return -EOPNOTSUPP;334 335	if (speed == 200 && port != 0)336		return -EOPNOTSUPP;337 338	if (speed == 2500 && port < 5)339		return -EOPNOTSUPP;340 341	return mv88e6xxx_port_set_speed_duplex(chip, port, speed, !port, true,342					       duplex);343}344 345phy_interface_t mv88e6341_port_max_speed_mode(struct mv88e6xxx_chip *chip,346					      int port)347{348	if (port == 5)349		return PHY_INTERFACE_MODE_2500BASEX;350 351	return PHY_INTERFACE_MODE_NA;352}353 354/* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */355int mv88e6352_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,356				    int speed, int duplex)357{358	if (speed > 1000)359		return -EOPNOTSUPP;360 361	if (speed == 200 && port < 5)362		return -EOPNOTSUPP;363 364	return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, false,365					       duplex);366}367 368/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */369int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,370				    int speed, int duplex)371{372	if (speed > 2500)373		return -EOPNOTSUPP;374 375	if (speed == 200 && port != 0)376		return -EOPNOTSUPP;377 378	if (speed == 2500 && port < 9)379		return -EOPNOTSUPP;380 381	return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true,382					       duplex);383}384 385phy_interface_t mv88e6390_port_max_speed_mode(struct mv88e6xxx_chip *chip,386					      int port)387{388	if (port == 9 || port == 10)389		return PHY_INTERFACE_MODE_2500BASEX;390 391	return PHY_INTERFACE_MODE_NA;392}393 394/* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */395int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,396				     int speed, int duplex)397{398	if (speed == 200 && port != 0)399		return -EOPNOTSUPP;400 401	if (speed >= 2500 && port < 9)402		return -EOPNOTSUPP;403 404	return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true,405					       duplex);406}407 408phy_interface_t mv88e6390x_port_max_speed_mode(struct mv88e6xxx_chip *chip,409					       int port)410{411	if (port == 9 || port == 10)412		return PHY_INTERFACE_MODE_XAUI;413 414	return PHY_INTERFACE_MODE_NA;415}416 417/* Support 10, 100, 200, 1000, 2500, 5000, 10000 Mbps (e.g. 88E6393X)418 * Function mv88e6xxx_port_set_speed_duplex() can't be used as the register419 * values for speeds 2500 & 5000 conflict.420 */421int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,422				     int speed, int duplex)423{424	u16 reg, ctrl;425	int err;426 427	if (chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361 &&428	    speed > 2500)429		return -EOPNOTSUPP;430 431	if (speed == 200 && port != 0)432		return -EOPNOTSUPP;433 434	if (speed >= 2500 && port > 0 && port < 9)435		return -EOPNOTSUPP;436 437	switch (speed) {438	case 10:439		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;440		break;441	case 100:442		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;443		break;444	case 200:445		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |446			MV88E6390_PORT_MAC_CTL_ALTSPEED;447		break;448	case 1000:449		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;450		break;451	case 2500:452		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000 |453			MV88E6390_PORT_MAC_CTL_ALTSPEED;454		break;455	case 5000:456		ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |457			MV88E6390_PORT_MAC_CTL_ALTSPEED;458		break;459	case 10000:460	case SPEED_UNFORCED:461		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;462		break;463	default:464		return -EOPNOTSUPP;465	}466 467	switch (duplex) {468	case DUPLEX_HALF:469		ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;470		break;471	case DUPLEX_FULL:472		ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |473			MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;474		break;475	case DUPLEX_UNFORCED:476		/* normal duplex detection */477		break;478	default:479		return -EOPNOTSUPP;480	}481 482	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);483	if (err)484		return err;485 486	reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |487		 MV88E6390_PORT_MAC_CTL_ALTSPEED |488		 MV88E6390_PORT_MAC_CTL_FORCE_SPEED);489 490	if (speed != SPEED_UNFORCED)491		reg |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;492 493	reg |= ctrl;494 495	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);496	if (err)497		return err;498 499	if (speed != SPEED_UNFORCED)500		dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);501	else502		dev_dbg(chip->dev, "p%d: Speed unforced\n", port);503	dev_dbg(chip->dev, "p%d: %s %s duplex\n", port,504		reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce",505		reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half");506 507	return 0;508}509 510phy_interface_t mv88e6393x_port_max_speed_mode(struct mv88e6xxx_chip *chip,511					       int port)512{513 514	if (port != 0 && port != 9 && port != 10)515		return PHY_INTERFACE_MODE_NA;516 517	if (chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361)518		return PHY_INTERFACE_MODE_2500BASEX;519 520	return PHY_INTERFACE_MODE_10GBASER;521}522 523static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,524				    phy_interface_t mode, bool force)525{526	u16 cmode;527	u16 reg;528	int err;529 530	/* Default to a slow mode, so freeing up SERDES interfaces for531	 * other ports which might use them for SFPs.532	 */533	if (mode == PHY_INTERFACE_MODE_NA)534		mode = PHY_INTERFACE_MODE_1000BASEX;535 536	switch (mode) {537	case PHY_INTERFACE_MODE_RMII:538		cmode = MV88E6XXX_PORT_STS_CMODE_RMII;539		break;540	case PHY_INTERFACE_MODE_RGMII:541	case PHY_INTERFACE_MODE_RGMII_ID:542	case PHY_INTERFACE_MODE_RGMII_RXID:543	case PHY_INTERFACE_MODE_RGMII_TXID:544		cmode = MV88E6XXX_PORT_STS_CMODE_RGMII;545		break;546	case PHY_INTERFACE_MODE_1000BASEX:547		cmode = MV88E6XXX_PORT_STS_CMODE_1000BASEX;548		break;549	case PHY_INTERFACE_MODE_SGMII:550		cmode = MV88E6XXX_PORT_STS_CMODE_SGMII;551		break;552	case PHY_INTERFACE_MODE_2500BASEX:553		cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;554		break;555	case PHY_INTERFACE_MODE_5GBASER:556		cmode = MV88E6393X_PORT_STS_CMODE_5GBASER;557		break;558	case PHY_INTERFACE_MODE_XGMII:559	case PHY_INTERFACE_MODE_XAUI:560		cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;561		break;562	case PHY_INTERFACE_MODE_RXAUI:563		cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI;564		break;565	case PHY_INTERFACE_MODE_10GBASER:566		cmode = MV88E6393X_PORT_STS_CMODE_10GBASER;567		break;568	case PHY_INTERFACE_MODE_USXGMII:569		cmode = MV88E6393X_PORT_STS_CMODE_USXGMII;570		break;571	default:572		cmode = 0;573	}574 575	/* cmode doesn't change, nothing to do for us unless forced */576	if (cmode == chip->ports[port].cmode && !force)577		return 0;578 579	chip->ports[port].cmode = 0;580 581	if (cmode) {582		err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);583		if (err)584			return err;585 586		reg &= ~MV88E6XXX_PORT_STS_CMODE_MASK;587		reg |= cmode;588 589		err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);590		if (err)591			return err;592 593		chip->ports[port].cmode = cmode;594	}595 596	return 0;597}598 599int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,600			      phy_interface_t mode)601{602	if (port != 9 && port != 10)603		return -EOPNOTSUPP;604 605	return mv88e6xxx_port_set_cmode(chip, port, mode, false);606}607 608int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,609			     phy_interface_t mode)610{611	if (port != 9 && port != 10)612		return -EOPNOTSUPP;613 614	switch (mode) {615	case PHY_INTERFACE_MODE_NA:616		return 0;617	case PHY_INTERFACE_MODE_XGMII:618	case PHY_INTERFACE_MODE_XAUI:619	case PHY_INTERFACE_MODE_RXAUI:620		return -EINVAL;621	default:622		break;623	}624 625	return mv88e6xxx_port_set_cmode(chip, port, mode, false);626}627 628int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,629			      phy_interface_t mode)630{631	int err;632	u16 reg;633 634	if (port != 0 && port != 9 && port != 10)635		return -EOPNOTSUPP;636 637	if (port == 9 || port == 10) {638		switch (mode) {639		case PHY_INTERFACE_MODE_RMII:640		case PHY_INTERFACE_MODE_RGMII:641		case PHY_INTERFACE_MODE_RGMII_ID:642		case PHY_INTERFACE_MODE_RGMII_RXID:643		case PHY_INTERFACE_MODE_RGMII_TXID:644			return -EINVAL;645		default:646			break;647		}648	}649 650	/* mv88e6393x errata 4.5: EEE should be disabled on SERDES ports */651	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);652	if (err)653		return err;654 655	reg &= ~MV88E6XXX_PORT_MAC_CTL_EEE;656	reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_EEE;657	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);658	if (err)659		return err;660 661	return mv88e6xxx_port_set_cmode(chip, port, mode, false);662}663 664static int mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip *chip,665					     int port)666{667	int err, addr;668	u16 reg, bits;669 670	if (port != 5)671		return -EOPNOTSUPP;672 673	addr = chip->info->port_base_addr + port;674 675	err = mv88e6xxx_port_hidden_read(chip, 0x7, addr, 0, &reg);676	if (err)677		return err;678 679	bits = MV88E6341_PORT_RESERVED_1A_FORCE_CMODE |680	       MV88E6341_PORT_RESERVED_1A_SGMII_AN;681 682	if ((reg & bits) == bits)683		return 0;684 685	reg |= bits;686	return mv88e6xxx_port_hidden_write(chip, 0x7, addr, 0, reg);687}688 689int mv88e6341_port_set_cmode(struct mv88e6xxx_chip *chip, int port,690			     phy_interface_t mode)691{692	int err;693 694	if (port != 5)695		return -EOPNOTSUPP;696 697	switch (mode) {698	case PHY_INTERFACE_MODE_NA:699		return 0;700	case PHY_INTERFACE_MODE_XGMII:701	case PHY_INTERFACE_MODE_XAUI:702	case PHY_INTERFACE_MODE_RXAUI:703		return -EINVAL;704	default:705		break;706	}707 708	err = mv88e6341_port_set_cmode_writable(chip, port);709	if (err)710		return err;711 712	return mv88e6xxx_port_set_cmode(chip, port, mode, true);713}714 715int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)716{717	int err;718	u16 reg;719 720	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);721	if (err)722		return err;723 724	*cmode = reg & MV88E6185_PORT_STS_CMODE_MASK;725 726	return 0;727}728 729int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)730{731	int err;732	u16 reg;733 734	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);735	if (err)736		return err;737 738	*cmode = reg & MV88E6XXX_PORT_STS_CMODE_MASK;739 740	return 0;741}742 743/* Offset 0x02: Jamming Control744 *745 * Do not limit the period of time that this port can be paused for by746 * the remote end or the period of time that this port can pause the747 * remote end.748 */749int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,750			       u8 out)751{752	return mv88e6xxx_port_write(chip, port, MV88E6097_PORT_JAM_CTL,753				    out << 8 | in);754}755 756int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,757			       u8 out)758{759	int err;760 761	err = mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,762				   MV88E6390_PORT_FLOW_CTL_UPDATE |763				   MV88E6390_PORT_FLOW_CTL_LIMIT_IN | in);764	if (err)765		return err;766 767	return mv88e6xxx_port_write(chip, port, MV88E6390_PORT_FLOW_CTL,768				    MV88E6390_PORT_FLOW_CTL_UPDATE |769				    MV88E6390_PORT_FLOW_CTL_LIMIT_OUT | out);770}771 772/* Offset 0x04: Port Control Register */773 774static const char * const mv88e6xxx_port_state_names[] = {775	[MV88E6XXX_PORT_CTL0_STATE_DISABLED] = "Disabled",776	[MV88E6XXX_PORT_CTL0_STATE_BLOCKING] = "Blocking/Listening",777	[MV88E6XXX_PORT_CTL0_STATE_LEARNING] = "Learning",778	[MV88E6XXX_PORT_CTL0_STATE_FORWARDING] = "Forwarding",779};780 781int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state)782{783	u16 reg;784	int err;785 786	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);787	if (err)788		return err;789 790	reg &= ~MV88E6XXX_PORT_CTL0_STATE_MASK;791 792	switch (state) {793	case BR_STATE_DISABLED:794		state = MV88E6XXX_PORT_CTL0_STATE_DISABLED;795		break;796	case BR_STATE_BLOCKING:797	case BR_STATE_LISTENING:798		state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING;799		break;800	case BR_STATE_LEARNING:801		state = MV88E6XXX_PORT_CTL0_STATE_LEARNING;802		break;803	case BR_STATE_FORWARDING:804		state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING;805		break;806	default:807		return -EINVAL;808	}809 810	reg |= state;811 812	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);813	if (err)814		return err;815 816	dev_dbg(chip->dev, "p%d: PortState set to %s\n", port,817		mv88e6xxx_port_state_names[state]);818 819	return 0;820}821 822int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port,823				   enum mv88e6xxx_egress_mode mode)824{825	int err;826	u16 reg;827 828	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);829	if (err)830		return err;831 832	reg &= ~MV88E6XXX_PORT_CTL0_EGRESS_MODE_MASK;833 834	switch (mode) {835	case MV88E6XXX_EGRESS_MODE_UNMODIFIED:836		reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNMODIFIED;837		break;838	case MV88E6XXX_EGRESS_MODE_UNTAGGED:839		reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNTAGGED;840		break;841	case MV88E6XXX_EGRESS_MODE_TAGGED:842		reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_TAGGED;843		break;844	case MV88E6XXX_EGRESS_MODE_ETHERTYPE:845		reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_ETHER_TYPE_DSA;846		break;847	default:848		return -EINVAL;849	}850 851	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);852}853 854int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,855				  enum mv88e6xxx_frame_mode mode)856{857	int err;858	u16 reg;859 860	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);861	if (err)862		return err;863 864	reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;865 866	switch (mode) {867	case MV88E6XXX_FRAME_MODE_NORMAL:868		reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;869		break;870	case MV88E6XXX_FRAME_MODE_DSA:871		reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;872		break;873	default:874		return -EINVAL;875	}876 877	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);878}879 880int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port,881				  enum mv88e6xxx_frame_mode mode)882{883	int err;884	u16 reg;885 886	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);887	if (err)888		return err;889 890	reg &= ~MV88E6XXX_PORT_CTL0_FRAME_MODE_MASK;891 892	switch (mode) {893	case MV88E6XXX_FRAME_MODE_NORMAL:894		reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_NORMAL;895		break;896	case MV88E6XXX_FRAME_MODE_DSA:897		reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_DSA;898		break;899	case MV88E6XXX_FRAME_MODE_PROVIDER:900		reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_PROVIDER;901		break;902	case MV88E6XXX_FRAME_MODE_ETHERTYPE:903		reg |= MV88E6XXX_PORT_CTL0_FRAME_MODE_ETHER_TYPE_DSA;904		break;905	default:906		return -EINVAL;907	}908 909	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);910}911 912int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip,913				       int port, bool unicast)914{915	int err;916	u16 reg;917 918	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);919	if (err)920		return err;921 922	if (unicast)923		reg |= MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;924	else925		reg &= ~MV88E6185_PORT_CTL0_FORWARD_UNKNOWN;926 927	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);928}929 930int mv88e6352_port_set_ucast_flood(struct mv88e6xxx_chip *chip, int port,931				   bool unicast)932{933	int err;934	u16 reg;935 936	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);937	if (err)938		return err;939 940	if (unicast)941		reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_UC;942	else943		reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_UC;944 945	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);946}947 948int mv88e6352_port_set_mcast_flood(struct mv88e6xxx_chip *chip, int port,949				   bool multicast)950{951	int err;952	u16 reg;953 954	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);955	if (err)956		return err;957 958	if (multicast)959		reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_MC;960	else961		reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_MC;962 963	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);964}965 966/* Offset 0x05: Port Control 1 */967 968int mv88e6xxx_port_set_message_port(struct mv88e6xxx_chip *chip, int port,969				    bool message_port)970{971	u16 val;972	int err;973 974	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val);975	if (err)976		return err;977 978	if (message_port)979		val |= MV88E6XXX_PORT_CTL1_MESSAGE_PORT;980	else981		val &= ~MV88E6XXX_PORT_CTL1_MESSAGE_PORT;982 983	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val);984}985 986int mv88e6xxx_port_set_trunk(struct mv88e6xxx_chip *chip, int port,987			     bool trunk, u8 id)988{989	u16 val;990	int err;991 992	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1, &val);993	if (err)994		return err;995 996	val &= ~MV88E6XXX_PORT_CTL1_TRUNK_ID_MASK;997 998	if (trunk)999		val |= MV88E6XXX_PORT_CTL1_TRUNK_PORT |1000			(id << MV88E6XXX_PORT_CTL1_TRUNK_ID_SHIFT);1001	else1002		val &= ~MV88E6XXX_PORT_CTL1_TRUNK_PORT;1003 1004	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1, val);1005}1006 1007/* Offset 0x06: Port Based VLAN Map */1008 1009int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map)1010{1011	const u16 mask = mv88e6xxx_port_mask(chip);1012	u16 reg;1013	int err;1014 1015	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);1016	if (err)1017		return err;1018 1019	reg &= ~mask;1020	reg |= map & mask;1021 1022	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);1023	if (err)1024		return err;1025 1026	dev_dbg(chip->dev, "p%d: VLANTable set to %.3x\n", port, map);1027 1028	return 0;1029}1030 1031int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid)1032{1033	const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;1034	u16 reg;1035	int err;1036 1037	/* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */1038	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);1039	if (err)1040		return err;1041 1042	*fid = (reg & 0xf000) >> 12;1043 1044	/* Port's default FID upper bits are located in reg 0x05, offset 0 */1045	if (upper_mask) {1046		err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,1047					  &reg);1048		if (err)1049			return err;1050 1051		*fid |= (reg & upper_mask) << 4;1052	}1053 1054	return 0;1055}1056 1057int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid)1058{1059	const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;1060	u16 reg;1061	int err;1062 1063	if (fid >= mv88e6xxx_num_databases(chip))1064		return -EINVAL;1065 1066	/* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */1067	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_BASE_VLAN, &reg);1068	if (err)1069		return err;1070 1071	reg &= 0x0fff;1072	reg |= (fid & 0x000f) << 12;1073 1074	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_BASE_VLAN, reg);1075	if (err)1076		return err;1077 1078	/* Port's default FID upper bits are located in reg 0x05, offset 0 */1079	if (upper_mask) {1080		err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL1,1081					  &reg);1082		if (err)1083			return err;1084 1085		reg &= ~upper_mask;1086		reg |= (fid >> 4) & upper_mask;1087 1088		err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL1,1089					   reg);1090		if (err)1091			return err;1092	}1093 1094	dev_dbg(chip->dev, "p%d: FID set to %u\n", port, fid);1095 1096	return 0;1097}1098 1099/* Offset 0x07: Default Port VLAN ID & Priority */1100 1101int mv88e6xxx_port_get_pvid(struct mv88e6xxx_chip *chip, int port, u16 *pvid)1102{1103	u16 reg;1104	int err;1105 1106	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,1107				  &reg);1108	if (err)1109		return err;1110 1111	*pvid = reg & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;1112 1113	return 0;1114}1115 1116int mv88e6xxx_port_set_pvid(struct mv88e6xxx_chip *chip, int port, u16 pvid)1117{1118	u16 reg;1119	int err;1120 1121	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,1122				  &reg);1123	if (err)1124		return err;1125 1126	reg &= ~MV88E6XXX_PORT_DEFAULT_VLAN_MASK;1127	reg |= pvid & MV88E6XXX_PORT_DEFAULT_VLAN_MASK;1128 1129	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_DEFAULT_VLAN,1130				   reg);1131	if (err)1132		return err;1133 1134	dev_dbg(chip->dev, "p%d: DefaultVID set to %u\n", port, pvid);1135 1136	return 0;1137}1138 1139/* Offset 0x08: Port Control 2 Register */1140 1141static const char * const mv88e6xxx_port_8021q_mode_names[] = {1142	[MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED] = "Disabled",1143	[MV88E6XXX_PORT_CTL2_8021Q_MODE_FALLBACK] = "Fallback",1144	[MV88E6XXX_PORT_CTL2_8021Q_MODE_CHECK] = "Check",1145	[MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE] = "Secure",1146};1147 1148int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip,1149				       int port, bool multicast)1150{1151	int err;1152	u16 reg;1153 1154	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);1155	if (err)1156		return err;1157 1158	if (multicast)1159		reg |= MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;1160	else1161		reg &= ~MV88E6XXX_PORT_CTL2_DEFAULT_FORWARD;1162 1163	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);1164}1165 1166int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,1167				     int upstream_port)1168{1169	int err;1170	u16 reg;1171 1172	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);1173	if (err)1174		return err;1175 1176	reg &= ~MV88E6095_PORT_CTL2_CPU_PORT_MASK;1177	reg |= upstream_port;1178 1179	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);1180}1181 1182int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port,1183			      enum mv88e6xxx_egress_direction direction,1184			      bool mirror)1185{1186	bool *mirror_port;1187	u16 reg;1188	u16 bit;1189	int err;1190 1191	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);1192	if (err)1193		return err;1194 1195	switch (direction) {1196	case MV88E6XXX_EGRESS_DIR_INGRESS:1197		bit = MV88E6XXX_PORT_CTL2_INGRESS_MONITOR;1198		mirror_port = &chip->ports[port].mirror_ingress;1199		break;1200	case MV88E6XXX_EGRESS_DIR_EGRESS:1201		bit = MV88E6XXX_PORT_CTL2_EGRESS_MONITOR;1202		mirror_port = &chip->ports[port].mirror_egress;1203		break;1204	default:1205		return -EINVAL;1206	}1207 1208	reg &= ~bit;1209	if (mirror)1210		reg |= bit;1211 1212	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);1213	if (!err)1214		*mirror_port = mirror;1215 1216	return err;1217}1218 1219int mv88e6xxx_port_set_lock(struct mv88e6xxx_chip *chip, int port,1220			    bool locked)1221{1222	u16 reg;1223	int err;1224 1225	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, &reg);1226	if (err)1227		return err;1228 1229	reg &= ~MV88E6XXX_PORT_CTL0_SA_FILT_MASK;1230	if (locked)1231		reg |= MV88E6XXX_PORT_CTL0_SA_FILT_DROP_ON_LOCK;1232 1233	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);1234	if (err)1235		return err;1236 1237	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, &reg);1238	if (err)1239		return err;1240 1241	reg &= ~MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;1242	if (locked)1243		reg |= MV88E6XXX_PORT_ASSOC_VECTOR_LOCKED_PORT;1244 1245	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, reg);1246}1247 1248int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,1249				  u16 mode)1250{1251	u16 reg;1252	int err;1253 1254	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);1255	if (err)1256		return err;1257 1258	reg &= ~MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;1259	reg |= mode & MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK;1260 1261	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);1262	if (err)1263		return err;1264 1265	dev_dbg(chip->dev, "p%d: 802.1QMode set to %s\n", port,1266		mv88e6xxx_port_8021q_mode_names[mode]);1267 1268	return 0;1269}1270 1271int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port,1272				 bool drop_untagged)1273{1274	u16 old, new;1275	int err;1276 1277	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &old);1278	if (err)1279		return err;1280 1281	if (drop_untagged)1282		new = old | MV88E6XXX_PORT_CTL2_DISCARD_UNTAGGED;1283	else1284		new = old & ~MV88E6XXX_PORT_CTL2_DISCARD_UNTAGGED;1285 1286	if (new == old)1287		return 0;1288 1289	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, new);1290}1291 1292int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port, bool map)1293{1294	u16 reg;1295	int err;1296 1297	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);1298	if (err)1299		return err;1300 1301	if (map)1302		reg |= MV88E6XXX_PORT_CTL2_MAP_DA;1303	else1304		reg &= ~MV88E6XXX_PORT_CTL2_MAP_DA;1305 1306	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);1307}1308 1309int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip *chip, int port,1310				  size_t size)1311{1312	u16 reg;1313	int err;1314 1315	size += VLAN_ETH_HLEN + ETH_FCS_LEN;1316 1317	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &reg);1318	if (err)1319		return err;1320 1321	reg &= ~MV88E6XXX_PORT_CTL2_JUMBO_MODE_MASK;1322 1323	if (size <= 1522)1324		reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_1522;1325	else if (size <= 2048)1326		reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_2048;1327	else if (size <= 10240)1328		reg |= MV88E6XXX_PORT_CTL2_JUMBO_MODE_10240;1329	else1330		return -ERANGE;1331 1332	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg);1333}1334 1335/* Offset 0x09: Port Rate Control */1336 1337int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)1338{1339	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,1340				    0x0000);1341}1342 1343int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int port)1344{1345	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_EGRESS_RATE_CTL1,1346				    0x0001);1347}1348 1349/* Offset 0x0B: Port Association Vector */1350 1351int mv88e6xxx_port_set_assoc_vector(struct mv88e6xxx_chip *chip, int port,1352				    u16 pav)1353{1354	u16 reg, mask;1355	int err;1356 1357	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,1358				  &reg);1359	if (err)1360		return err;1361 1362	mask = mv88e6xxx_port_mask(chip);1363	reg &= ~mask;1364	reg |= pav & mask;1365 1366	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,1367				    reg);1368}1369 1370/* Offset 0x0C: Port ATU Control */1371 1372int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port)1373{1374	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ATU_CTL, 0);1375}1376 1377/* Offset 0x0D: (Priority) Override Register */1378 1379int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port)1380{1381	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0);1382}1383 1384/* Offset 0x0E: Policy & MGMT Control Register for FAMILY 6191X 6193X 6393X */1385 1386static int mv88e6393x_port_policy_read(struct mv88e6xxx_chip *chip, int port,1387				       u16 pointer, u8 *data)1388{1389	u16 reg;1390	int err;1391 1392	err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL,1393				   pointer);1394	if (err)1395		return err;1396 1397	err = mv88e6xxx_port_read(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL,1398				  &reg);1399	if (err)1400		return err;1401 1402	*data = reg;1403 1404	return 0;1405}1406 1407static int mv88e6393x_port_policy_write(struct mv88e6xxx_chip *chip, int port,1408					u16 pointer, u8 data)1409{1410	u16 reg;1411 1412	reg = MV88E6393X_PORT_POLICY_MGMT_CTL_UPDATE | pointer | data;1413 1414	return mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL,1415				    reg);1416}1417 1418static int mv88e6393x_port_policy_write_all(struct mv88e6xxx_chip *chip,1419					    u16 pointer, u8 data)1420{1421	int err, port;1422 1423	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {1424		if (dsa_is_unused_port(chip->ds, port))1425			continue;1426 1427		err = mv88e6393x_port_policy_write(chip, port, pointer, data);1428		if (err)1429			return err;1430	}1431 1432	return 0;1433}1434 1435int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip,1436			       enum mv88e6xxx_egress_direction direction,1437			       int port)1438{1439	u16 ptr;1440	int err;1441 1442	switch (direction) {1443	case MV88E6XXX_EGRESS_DIR_INGRESS:1444		ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_INGRESS_DEST;1445		err = mv88e6393x_port_policy_write_all(chip, ptr, port);1446		if (err)1447			return err;1448		break;1449	case MV88E6XXX_EGRESS_DIR_EGRESS:1450		ptr = MV88E6393X_G2_EGRESS_MONITOR_DEST;1451		err = mv88e6xxx_g2_write(chip, ptr, port);1452		if (err)1453			return err;1454		break;1455	}1456 1457	return 0;1458}1459 1460int mv88e6393x_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,1461				      int upstream_port)1462{1463	u16 ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_CPU_DEST;1464	u8 data = MV88E6393X_PORT_POLICY_MGMT_CTL_CPU_DEST_MGMTPRI |1465		  upstream_port;1466 1467	return mv88e6393x_port_policy_write(chip, port, ptr, data);1468}1469 1470int mv88e6393x_port_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)1471{1472	u16 ptr;1473	int err;1474 1475	/* Consider the frames with reserved multicast destination1476	 * addresses matching 01:80:c2:00:00:00 and1477	 * 01:80:c2:00:00:02 as MGMT.1478	 */1479	ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XLO;1480	err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);1481	if (err)1482		return err;1483 1484	ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XHI;1485	err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);1486	if (err)1487		return err;1488 1489	ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XLO;1490	err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);1491	if (err)1492		return err;1493 1494	ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XHI;1495	err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);1496	if (err)1497		return err;1498 1499	return 0;1500}1501 1502/* Offset 0x10 & 0x11: EPC */1503 1504static int mv88e6393x_port_epc_wait_ready(struct mv88e6xxx_chip *chip, int port)1505{1506	int bit = __bf_shf(MV88E6393X_PORT_EPC_CMD_BUSY);1507 1508	return mv88e6xxx_port_wait_bit(chip, port, MV88E6393X_PORT_EPC_CMD, bit, 0);1509}1510 1511/* Port Ether type for 6393X family */1512 1513int mv88e6393x_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,1514				   u16 etype)1515{1516	u16 val;1517	int err;1518 1519	err = mv88e6393x_port_epc_wait_ready(chip, port);1520	if (err)1521		return err;1522 1523	err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_DATA, etype);1524	if (err)1525		return err;1526 1527	val = MV88E6393X_PORT_EPC_CMD_BUSY |1528	      MV88E6393X_PORT_EPC_CMD_WRITE |1529	      MV88E6393X_PORT_EPC_INDEX_PORT_ETYPE;1530 1531	return mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_CMD, val);1532}1533 1534/* Offset 0x0f: Port Ether type */1535 1536int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,1537				  u16 etype)1538{1539	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype);1540}1541 1542/* Offset 0x18: Port IEEE Priority Remapping Registers [0-3]1543 * Offset 0x19: Port IEEE Priority Remapping Registers [4-7]1544 */1545 1546int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port)1547{1548	int err;1549 1550	/* Use a direct priority mapping for all IEEE tagged frames */1551	err = mv88e6xxx_port_write(chip, port,1552				   MV88E6095_PORT_IEEE_PRIO_REMAP_0123,1553				   0x3210);1554	if (err)1555		return err;1556 1557	return mv88e6xxx_port_write(chip, port,1558				    MV88E6095_PORT_IEEE_PRIO_REMAP_4567,1559				    0x7654);1560}1561 1562static int mv88e6xxx_port_ieeepmt_write(struct mv88e6xxx_chip *chip,1563					int port, u16 table, u8 ptr, u16 data)1564{1565	u16 reg;1566 1567	reg = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE | table |1568		(ptr << __bf_shf(MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_PTR_MASK)) |1569		(data & MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_DATA_MASK);1570 1571	return mv88e6xxx_port_write(chip, port,1572				    MV88E6390_PORT_IEEE_PRIO_MAP_TABLE, reg);1573}1574 1575int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port)1576{1577	int err, i;1578	u16 table;1579 1580	for (i = 0; i <= 7; i++) {1581		table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP;1582		err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i,1583						   (i | i << 4));1584		if (err)1585			return err;1586 1587		table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP;1588		err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);1589		if (err)1590			return err;1591 1592		table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP;1593		err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);1594		if (err)1595			return err;1596 1597		table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP;1598		err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i);1599		if (err)1600			return err;1601	}1602 1603	return 0;1604}1605 1606/* Offset 0x0E: Policy Control Register */1607 1608static int1609mv88e6xxx_port_policy_mapping_get_pos(enum mv88e6xxx_policy_mapping mapping,1610				      enum mv88e6xxx_policy_action action,1611				      u16 *mask, u16 *val, int *shift)1612{1613	switch (mapping) {1614	case MV88E6XXX_POLICY_MAPPING_DA:1615		*shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_DA_MASK);1616		*mask = MV88E6XXX_PORT_POLICY_CTL_DA_MASK;1617		break;1618	case MV88E6XXX_POLICY_MAPPING_SA:1619		*shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_SA_MASK);1620		*mask = MV88E6XXX_PORT_POLICY_CTL_SA_MASK;1621		break;1622	case MV88E6XXX_POLICY_MAPPING_VTU:1623		*shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VTU_MASK);1624		*mask = MV88E6XXX_PORT_POLICY_CTL_VTU_MASK;1625		break;1626	case MV88E6XXX_POLICY_MAPPING_ETYPE:1627		*shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK);1628		*mask = MV88E6XXX_PORT_POLICY_CTL_ETYPE_MASK;1629		break;1630	case MV88E6XXX_POLICY_MAPPING_PPPOE:1631		*shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK);1632		*mask = MV88E6XXX_PORT_POLICY_CTL_PPPOE_MASK;1633		break;1634	case MV88E6XXX_POLICY_MAPPING_VBAS:1635		*shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK);1636		*mask = MV88E6XXX_PORT_POLICY_CTL_VBAS_MASK;1637		break;1638	case MV88E6XXX_POLICY_MAPPING_OPT82:1639		*shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK);1640		*mask = MV88E6XXX_PORT_POLICY_CTL_OPT82_MASK;1641		break;1642	case MV88E6XXX_POLICY_MAPPING_UDP:1643		*shift = __bf_shf(MV88E6XXX_PORT_POLICY_CTL_UDP_MASK);1644		*mask = MV88E6XXX_PORT_POLICY_CTL_UDP_MASK;1645		break;1646	default:1647		return -EOPNOTSUPP;1648	}1649 1650	switch (action) {1651	case MV88E6XXX_POLICY_ACTION_NORMAL:1652		*val = MV88E6XXX_PORT_POLICY_CTL_NORMAL;1653		break;1654	case MV88E6XXX_POLICY_ACTION_MIRROR:1655		*val = MV88E6XXX_PORT_POLICY_CTL_MIRROR;1656		break;1657	case MV88E6XXX_POLICY_ACTION_TRAP:1658		*val = MV88E6XXX_PORT_POLICY_CTL_TRAP;1659		break;1660	case MV88E6XXX_POLICY_ACTION_DISCARD:1661		*val = MV88E6XXX_PORT_POLICY_CTL_DISCARD;1662		break;1663	default:1664		return -EOPNOTSUPP;1665	}1666 1667	return 0;1668}1669 1670int mv88e6352_port_set_policy(struct mv88e6xxx_chip *chip, int port,1671			      enum mv88e6xxx_policy_mapping mapping,1672			      enum mv88e6xxx_policy_action action)1673{1674	u16 reg, mask, val;1675	int shift;1676	int err;1677 1678	err = mv88e6xxx_port_policy_mapping_get_pos(mapping, action, &mask,1679						    &val, &shift);1680	if (err)1681		return err;1682 1683	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_POLICY_CTL, &reg);1684	if (err)1685		return err;1686 1687	reg &= ~mask;1688	reg |= (val << shift) & mask;1689 1690	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_POLICY_CTL, reg);1691}1692 1693int mv88e6393x_port_set_policy(struct mv88e6xxx_chip *chip, int port,1694			       enum mv88e6xxx_policy_mapping mapping,1695			       enum mv88e6xxx_policy_action action)1696{1697	u16 mask, val;1698	int shift;1699	int err;1700	u16 ptr;1701	u8 reg;1702 1703	err = mv88e6xxx_port_policy_mapping_get_pos(mapping, action, &mask,1704						    &val, &shift);1705	if (err)1706		return err;1707 1708	/* The 16-bit Port Policy CTL register from older chips is on 6393x1709	 * changed to Port Policy MGMT CTL, which can access more data, but1710	 * indirectly. The original 16-bit value is divided into two 8-bit1711	 * registers.1712	 */1713	ptr = shift / 8;1714	shift %= 8;1715	mask >>= ptr * 8;1716	ptr <<= 8;1717 1718	err = mv88e6393x_port_policy_read(chip, port, ptr, &reg);1719	if (err)1720		return err;1721 1722	reg &= ~mask;1723	reg |= (val << shift) & mask;1724 1725	return mv88e6393x_port_policy_write(chip, port, ptr, reg);1726}1727