xref: /rk3399_rockchip-uboot/drivers/net/vsc9953.c (revision 43d3fb5c0609a76409e7859a2a5800670c7b5bd2)
16706b115SCodrin Ciubotariu /*
2a857d5f8SCodrin Ciubotariu  *  Copyright 2014 - 2015 Freescale Semiconductor, Inc.
36706b115SCodrin Ciubotariu  *
46706b115SCodrin Ciubotariu  *  SPDX-License-Identifier:      GPL-2.0+
56706b115SCodrin Ciubotariu  *
66706b115SCodrin Ciubotariu  *  Driver for the Vitesse VSC9953 L2 Switch
76706b115SCodrin Ciubotariu  */
86706b115SCodrin Ciubotariu 
96706b115SCodrin Ciubotariu #include <asm/io.h>
106706b115SCodrin Ciubotariu #include <asm/fsl_serdes.h>
116706b115SCodrin Ciubotariu #include <fm_eth.h>
12cd348efaSShaohui Xie #include <fsl_memac.h>
139de05987SCodrin Ciubotariu #include <bitfield.h>
143cc8cfffSCodrin Ciubotariu #include <errno.h>
153cc8cfffSCodrin Ciubotariu #include <malloc.h>
166706b115SCodrin Ciubotariu #include <vsc9953.h>
1724a23debSCodrin Ciubotariu #include <ethsw.h>
186706b115SCodrin Ciubotariu 
196706b115SCodrin Ciubotariu static struct vsc9953_info vsc9953_l2sw = {
206706b115SCodrin Ciubotariu 		.port[0] = VSC9953_PORT_INFO_INITIALIZER(0),
216706b115SCodrin Ciubotariu 		.port[1] = VSC9953_PORT_INFO_INITIALIZER(1),
226706b115SCodrin Ciubotariu 		.port[2] = VSC9953_PORT_INFO_INITIALIZER(2),
236706b115SCodrin Ciubotariu 		.port[3] = VSC9953_PORT_INFO_INITIALIZER(3),
246706b115SCodrin Ciubotariu 		.port[4] = VSC9953_PORT_INFO_INITIALIZER(4),
256706b115SCodrin Ciubotariu 		.port[5] = VSC9953_PORT_INFO_INITIALIZER(5),
266706b115SCodrin Ciubotariu 		.port[6] = VSC9953_PORT_INFO_INITIALIZER(6),
276706b115SCodrin Ciubotariu 		.port[7] = VSC9953_PORT_INFO_INITIALIZER(7),
286706b115SCodrin Ciubotariu 		.port[8] = VSC9953_PORT_INFO_INITIALIZER(8),
296706b115SCodrin Ciubotariu 		.port[9] = VSC9953_PORT_INFO_INITIALIZER(9),
306706b115SCodrin Ciubotariu };
316706b115SCodrin Ciubotariu 
vsc9953_port_info_set_mdio(int port_no,struct mii_dev * bus)323cc8cfffSCodrin Ciubotariu void vsc9953_port_info_set_mdio(int port_no, struct mii_dev *bus)
336706b115SCodrin Ciubotariu {
343cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
356706b115SCodrin Ciubotariu 		return;
366706b115SCodrin Ciubotariu 
373cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].bus = bus;
386706b115SCodrin Ciubotariu }
396706b115SCodrin Ciubotariu 
vsc9953_port_info_set_phy_address(int port_no,int address)403cc8cfffSCodrin Ciubotariu void vsc9953_port_info_set_phy_address(int port_no, int address)
416706b115SCodrin Ciubotariu {
423cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
436706b115SCodrin Ciubotariu 		return;
446706b115SCodrin Ciubotariu 
453cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].phyaddr = address;
466706b115SCodrin Ciubotariu }
476706b115SCodrin Ciubotariu 
vsc9953_port_info_set_phy_int(int port_no,phy_interface_t phy_int)483cc8cfffSCodrin Ciubotariu void vsc9953_port_info_set_phy_int(int port_no, phy_interface_t phy_int)
496706b115SCodrin Ciubotariu {
503cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
516706b115SCodrin Ciubotariu 		return;
526706b115SCodrin Ciubotariu 
533cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].enet_if = phy_int;
546706b115SCodrin Ciubotariu }
556706b115SCodrin Ciubotariu 
vsc9953_port_enable(int port_no)563cc8cfffSCodrin Ciubotariu void vsc9953_port_enable(int port_no)
576706b115SCodrin Ciubotariu {
583cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
596706b115SCodrin Ciubotariu 		return;
606706b115SCodrin Ciubotariu 
613cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].enabled = 1;
626706b115SCodrin Ciubotariu }
636706b115SCodrin Ciubotariu 
vsc9953_port_disable(int port_no)643cc8cfffSCodrin Ciubotariu void vsc9953_port_disable(int port_no)
656706b115SCodrin Ciubotariu {
663cc8cfffSCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
676706b115SCodrin Ciubotariu 		return;
686706b115SCodrin Ciubotariu 
693cc8cfffSCodrin Ciubotariu 	vsc9953_l2sw.port[port_no].enabled = 0;
706706b115SCodrin Ciubotariu }
716706b115SCodrin Ciubotariu 
vsc9953_mdio_write(struct vsc9953_mii_mng * phyregs,int port_addr,int regnum,int value)726706b115SCodrin Ciubotariu static void vsc9953_mdio_write(struct vsc9953_mii_mng *phyregs, int port_addr,
736706b115SCodrin Ciubotariu 		int regnum, int value)
746706b115SCodrin Ciubotariu {
756706b115SCodrin Ciubotariu 	int timeout = 50000;
766706b115SCodrin Ciubotariu 
776706b115SCodrin Ciubotariu 	out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) |
786706b115SCodrin Ciubotariu 			((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) |
796706b115SCodrin Ciubotariu 			(0x1 << 1));
806706b115SCodrin Ciubotariu 	asm("sync");
816706b115SCodrin Ciubotariu 
826706b115SCodrin Ciubotariu 	while ((in_le32(&phyregs->miimstatus) & 0x8) && --timeout)
836706b115SCodrin Ciubotariu 		udelay(1);
846706b115SCodrin Ciubotariu 
856706b115SCodrin Ciubotariu 	if (timeout == 0)
866706b115SCodrin Ciubotariu 		debug("Timeout waiting for MDIO write\n");
876706b115SCodrin Ciubotariu }
886706b115SCodrin Ciubotariu 
vsc9953_mdio_read(struct vsc9953_mii_mng * phyregs,int port_addr,int regnum)896706b115SCodrin Ciubotariu static int vsc9953_mdio_read(struct vsc9953_mii_mng *phyregs, int port_addr,
906706b115SCodrin Ciubotariu 		int regnum)
916706b115SCodrin Ciubotariu {
926706b115SCodrin Ciubotariu 	int value = 0xFFFF;
936706b115SCodrin Ciubotariu 	int timeout = 50000;
946706b115SCodrin Ciubotariu 
956706b115SCodrin Ciubotariu 	while ((in_le32(&phyregs->miimstatus) & MIIMIND_OPR_PEND) && --timeout)
966706b115SCodrin Ciubotariu 		udelay(1);
976706b115SCodrin Ciubotariu 	if (timeout == 0) {
986706b115SCodrin Ciubotariu 		debug("Timeout waiting for MDIO operation to finish\n");
996706b115SCodrin Ciubotariu 		return value;
1006706b115SCodrin Ciubotariu 	}
1016706b115SCodrin Ciubotariu 
1026706b115SCodrin Ciubotariu 	/* Put the address of the phy, and the register
1036706b115SCodrin Ciubotariu 	 * number into MIICMD
1046706b115SCodrin Ciubotariu 	 */
1056706b115SCodrin Ciubotariu 	out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) |
1066706b115SCodrin Ciubotariu 			((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) |
1076706b115SCodrin Ciubotariu 			(0x2 << 1));
1086706b115SCodrin Ciubotariu 
1096706b115SCodrin Ciubotariu 	timeout = 50000;
1106706b115SCodrin Ciubotariu 	/* Wait for the the indication that the read is done */
1116706b115SCodrin Ciubotariu 	while ((in_le32(&phyregs->miimstatus) & 0x8) && --timeout)
1126706b115SCodrin Ciubotariu 		udelay(1);
1136706b115SCodrin Ciubotariu 	if (timeout == 0)
1146706b115SCodrin Ciubotariu 		debug("Timeout waiting for MDIO read\n");
1156706b115SCodrin Ciubotariu 
1166706b115SCodrin Ciubotariu 	/* Grab the value read from the PHY */
1176706b115SCodrin Ciubotariu 	value = in_le32(&phyregs->miimdata);
1186706b115SCodrin Ciubotariu 
1196706b115SCodrin Ciubotariu 	if ((value & 0x00030000) == 0)
1206706b115SCodrin Ciubotariu 		return value & 0x0000ffff;
1216706b115SCodrin Ciubotariu 
1226706b115SCodrin Ciubotariu 	return value;
1236706b115SCodrin Ciubotariu }
1246706b115SCodrin Ciubotariu 
init_phy(struct eth_device * dev)1256706b115SCodrin Ciubotariu static int init_phy(struct eth_device *dev)
1266706b115SCodrin Ciubotariu {
1276706b115SCodrin Ciubotariu 	struct vsc9953_port_info *l2sw_port = dev->priv;
1286706b115SCodrin Ciubotariu 	struct phy_device *phydev = NULL;
1296706b115SCodrin Ciubotariu 
1306706b115SCodrin Ciubotariu #ifdef CONFIG_PHYLIB
1316706b115SCodrin Ciubotariu 	if (!l2sw_port->bus)
1326706b115SCodrin Ciubotariu 		return 0;
1336706b115SCodrin Ciubotariu 	phydev = phy_connect(l2sw_port->bus, l2sw_port->phyaddr, dev,
1346706b115SCodrin Ciubotariu 			l2sw_port->enet_if);
1356706b115SCodrin Ciubotariu 	if (!phydev) {
1366706b115SCodrin Ciubotariu 		printf("Failed to connect\n");
1376706b115SCodrin Ciubotariu 		return -1;
1386706b115SCodrin Ciubotariu 	}
1396706b115SCodrin Ciubotariu 
1406706b115SCodrin Ciubotariu 	phydev->supported &= SUPPORTED_10baseT_Half |
1416706b115SCodrin Ciubotariu 			SUPPORTED_10baseT_Full |
1426706b115SCodrin Ciubotariu 			SUPPORTED_100baseT_Half |
1436706b115SCodrin Ciubotariu 			SUPPORTED_100baseT_Full |
1446706b115SCodrin Ciubotariu 			SUPPORTED_1000baseT_Full;
1456706b115SCodrin Ciubotariu 	phydev->advertising = phydev->supported;
1466706b115SCodrin Ciubotariu 
1476706b115SCodrin Ciubotariu 	l2sw_port->phydev = phydev;
1486706b115SCodrin Ciubotariu 
1496706b115SCodrin Ciubotariu 	phy_config(phydev);
1506706b115SCodrin Ciubotariu #endif
1516706b115SCodrin Ciubotariu 
1526706b115SCodrin Ciubotariu 	return 0;
1536706b115SCodrin Ciubotariu }
1546706b115SCodrin Ciubotariu 
vsc9953_port_init(int port_no)1553cc8cfffSCodrin Ciubotariu static int vsc9953_port_init(int port_no)
1566706b115SCodrin Ciubotariu {
1576706b115SCodrin Ciubotariu 	struct eth_device *dev;
1586706b115SCodrin Ciubotariu 
1596706b115SCodrin Ciubotariu 	/* Internal ports never have a PHY */
1603cc8cfffSCodrin Ciubotariu 	if (VSC9953_INTERNAL_PORT_CHECK(port_no))
1616706b115SCodrin Ciubotariu 		return 0;
1626706b115SCodrin Ciubotariu 
1636706b115SCodrin Ciubotariu 	/* alloc eth device */
1646706b115SCodrin Ciubotariu 	dev = (struct eth_device *)calloc(1, sizeof(struct eth_device));
1656706b115SCodrin Ciubotariu 	if (!dev)
1663cc8cfffSCodrin Ciubotariu 		return -ENOMEM;
1676706b115SCodrin Ciubotariu 
1683cc8cfffSCodrin Ciubotariu 	sprintf(dev->name, "SW@PORT%d", port_no);
1693cc8cfffSCodrin Ciubotariu 	dev->priv = &vsc9953_l2sw.port[port_no];
1706706b115SCodrin Ciubotariu 	dev->init = NULL;
1716706b115SCodrin Ciubotariu 	dev->halt = NULL;
1726706b115SCodrin Ciubotariu 	dev->send = NULL;
1736706b115SCodrin Ciubotariu 	dev->recv = NULL;
1746706b115SCodrin Ciubotariu 
1756706b115SCodrin Ciubotariu 	if (init_phy(dev)) {
1766706b115SCodrin Ciubotariu 		free(dev);
1773cc8cfffSCodrin Ciubotariu 		return -ENODEV;
1786706b115SCodrin Ciubotariu 	}
1796706b115SCodrin Ciubotariu 
1806706b115SCodrin Ciubotariu 	return 0;
1816706b115SCodrin Ciubotariu }
1826706b115SCodrin Ciubotariu 
vsc9953_vlan_table_poll_idle(void)1839de05987SCodrin Ciubotariu static int vsc9953_vlan_table_poll_idle(void)
1849de05987SCodrin Ciubotariu {
1859de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
1869de05987SCodrin Ciubotariu 	int timeout;
1879de05987SCodrin Ciubotariu 
1889de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1899de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
1909de05987SCodrin Ciubotariu 
1919de05987SCodrin Ciubotariu 	timeout = 50000;
1929de05987SCodrin Ciubotariu 	while (((in_le32(&l2ana_reg->ana_tables.vlan_access) &
1939de05987SCodrin Ciubotariu 		 VSC9953_VLAN_CMD_MASK) != VSC9953_VLAN_CMD_IDLE) && --timeout)
1949de05987SCodrin Ciubotariu 		udelay(1);
1959de05987SCodrin Ciubotariu 
1969de05987SCodrin Ciubotariu 	return timeout ? 0 : -EBUSY;
1979de05987SCodrin Ciubotariu }
1989de05987SCodrin Ciubotariu 
199a2477924SCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
200a2477924SCodrin Ciubotariu /* Add/remove a port to/from a VLAN */
vsc9953_vlan_table_membership_set(int vid,u32 port_no,u8 add)201a2477924SCodrin Ciubotariu static void vsc9953_vlan_table_membership_set(int vid, u32 port_no, u8 add)
202a2477924SCodrin Ciubotariu {
203a2477924SCodrin Ciubotariu 	u32 val;
204a2477924SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
205a2477924SCodrin Ciubotariu 
206a2477924SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
207a2477924SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
208a2477924SCodrin Ciubotariu 
209a2477924SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
210a2477924SCodrin Ciubotariu 		debug("VLAN table timeout\n");
211a2477924SCodrin Ciubotariu 		return;
212a2477924SCodrin Ciubotariu 	}
213a2477924SCodrin Ciubotariu 
214a2477924SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
215a2477924SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid);
216a2477924SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
217a2477924SCodrin Ciubotariu 
218a2477924SCodrin Ciubotariu 	clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
219a2477924SCodrin Ciubotariu 			VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
220a2477924SCodrin Ciubotariu 
221a2477924SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
222a2477924SCodrin Ciubotariu 		debug("VLAN table timeout\n");
223a2477924SCodrin Ciubotariu 		return;
224a2477924SCodrin Ciubotariu 	}
225a2477924SCodrin Ciubotariu 
226a2477924SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
227a2477924SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid);
228a2477924SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
229a2477924SCodrin Ciubotariu 
230a2477924SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_access);
231a2477924SCodrin Ciubotariu 	if (!add) {
232a2477924SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_VLAN_CMD_MASK,
233a2477924SCodrin Ciubotariu 						VSC9953_VLAN_CMD_WRITE) &
234a2477924SCodrin Ciubotariu 		      ~(bitfield_replace_by_mask(0, VSC9953_VLAN_PORT_MASK,
235a2477924SCodrin Ciubotariu 						 (1 << port_no)));
236a2477924SCodrin Ciubotariu 		 ;
237a2477924SCodrin Ciubotariu 	} else {
238a2477924SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_VLAN_CMD_MASK,
239a2477924SCodrin Ciubotariu 						VSC9953_VLAN_CMD_WRITE) |
240a2477924SCodrin Ciubotariu 		      bitfield_replace_by_mask(0, VSC9953_VLAN_PORT_MASK,
241a2477924SCodrin Ciubotariu 					       (1 << port_no));
242a2477924SCodrin Ciubotariu 	}
243a2477924SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_access, val);
244a2477924SCodrin Ciubotariu 
245a2477924SCodrin Ciubotariu 	/* wait for VLAN table command to flush */
246a2477924SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
247a2477924SCodrin Ciubotariu 		debug("VLAN table timeout\n");
248a2477924SCodrin Ciubotariu 		return;
249a2477924SCodrin Ciubotariu 	}
250a2477924SCodrin Ciubotariu }
251a2477924SCodrin Ciubotariu 
252a2477924SCodrin Ciubotariu /* show VLAN membership for a port */
vsc9953_vlan_membership_show(int port_no)253a2477924SCodrin Ciubotariu static void vsc9953_vlan_membership_show(int port_no)
254a2477924SCodrin Ciubotariu {
255a2477924SCodrin Ciubotariu 	u32 val;
256a2477924SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
257a2477924SCodrin Ciubotariu 	u32 vid;
258a2477924SCodrin Ciubotariu 
259a2477924SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
260a2477924SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
261a2477924SCodrin Ciubotariu 
262a2477924SCodrin Ciubotariu 	printf("Port %d VLAN membership: ", port_no);
263a2477924SCodrin Ciubotariu 
264a2477924SCodrin Ciubotariu 	for (vid = 0; vid < VSC9953_MAX_VLAN; vid++) {
265a2477924SCodrin Ciubotariu 		if (vsc9953_vlan_table_poll_idle() < 0) {
266a2477924SCodrin Ciubotariu 			debug("VLAN table timeout\n");
267a2477924SCodrin Ciubotariu 			return;
268a2477924SCodrin Ciubotariu 		}
269a2477924SCodrin Ciubotariu 
270a2477924SCodrin Ciubotariu 		val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
271a2477924SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK,
272a2477924SCodrin Ciubotariu 					       vid);
273a2477924SCodrin Ciubotariu 		out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
274a2477924SCodrin Ciubotariu 
275a2477924SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
276a2477924SCodrin Ciubotariu 				VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
277a2477924SCodrin Ciubotariu 
278a2477924SCodrin Ciubotariu 		if (vsc9953_vlan_table_poll_idle() < 0) {
279a2477924SCodrin Ciubotariu 			debug("VLAN table timeout\n");
280a2477924SCodrin Ciubotariu 			return;
281a2477924SCodrin Ciubotariu 		}
282a2477924SCodrin Ciubotariu 
283a2477924SCodrin Ciubotariu 		val = in_le32(&l2ana_reg->ana_tables.vlan_access);
284a2477924SCodrin Ciubotariu 
285a2477924SCodrin Ciubotariu 		if (bitfield_extract_by_mask(val, VSC9953_VLAN_PORT_MASK) &
286a2477924SCodrin Ciubotariu 		    (1 << port_no))
287a2477924SCodrin Ciubotariu 			printf("%d ", vid);
288a2477924SCodrin Ciubotariu 	}
289a2477924SCodrin Ciubotariu 	printf("\n");
290a2477924SCodrin Ciubotariu }
291a2477924SCodrin Ciubotariu #endif
292a2477924SCodrin Ciubotariu 
2939de05987SCodrin Ciubotariu /* vlan table set/clear all membership of vid */
vsc9953_vlan_table_membership_all_set(int vid,int set_member)2949de05987SCodrin Ciubotariu static void vsc9953_vlan_table_membership_all_set(int vid, int set_member)
2959de05987SCodrin Ciubotariu {
2969de05987SCodrin Ciubotariu 	uint val;
2979de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
2989de05987SCodrin Ciubotariu 
2999de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
3009de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
3019de05987SCodrin Ciubotariu 
3029de05987SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
3039de05987SCodrin Ciubotariu 		debug("VLAN table timeout\n");
3049de05987SCodrin Ciubotariu 		return;
3059de05987SCodrin Ciubotariu 	}
3069de05987SCodrin Ciubotariu 
3079de05987SCodrin Ciubotariu 	/* read current vlan configuration */
3089de05987SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
3099de05987SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_tidx,
3109de05987SCodrin Ciubotariu 		 bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid));
3119de05987SCodrin Ciubotariu 
3129de05987SCodrin Ciubotariu 	clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
3139de05987SCodrin Ciubotariu 			VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
3149de05987SCodrin Ciubotariu 
3159de05987SCodrin Ciubotariu 	if (vsc9953_vlan_table_poll_idle() < 0) {
3169de05987SCodrin Ciubotariu 		debug("VLAN table timeout\n");
3179de05987SCodrin Ciubotariu 		return;
3189de05987SCodrin Ciubotariu 	}
3199de05987SCodrin Ciubotariu 
3209de05987SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
3219de05987SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.vlan_tidx,
3229de05987SCodrin Ciubotariu 		 bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid));
3239de05987SCodrin Ciubotariu 
3249de05987SCodrin Ciubotariu 	clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
3259de05987SCodrin Ciubotariu 			VSC9953_VLAN_PORT_MASK | VSC9953_VLAN_CMD_MASK,
3269de05987SCodrin Ciubotariu 			VSC9953_VLAN_CMD_WRITE |
3279de05987SCodrin Ciubotariu 			(set_member ? VSC9953_VLAN_PORT_MASK : 0));
3289de05987SCodrin Ciubotariu }
3299de05987SCodrin Ciubotariu 
330a2477924SCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
331a2477924SCodrin Ciubotariu /* Get PVID of a VSC9953 port */
vsc9953_port_vlan_pvid_get(int port_nr,int * pvid)332a2477924SCodrin Ciubotariu static int vsc9953_port_vlan_pvid_get(int port_nr, int *pvid)
333a2477924SCodrin Ciubotariu {
334a2477924SCodrin Ciubotariu 	u32 val;
335a2477924SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
336a2477924SCodrin Ciubotariu 
337a2477924SCodrin Ciubotariu 	/* Administrative down */
338*9101a68cSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_nr].enabled) {
339a2477924SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_nr);
340a2477924SCodrin Ciubotariu 		return -1;
341a2477924SCodrin Ciubotariu 	}
342a2477924SCodrin Ciubotariu 
343a2477924SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
344a2477924SCodrin Ciubotariu 				VSC9953_ANA_OFFSET);
345a2477924SCodrin Ciubotariu 
346a2477924SCodrin Ciubotariu 	/* Get ingress PVID */
347a2477924SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_nr].vlan_cfg);
348a2477924SCodrin Ciubotariu 	*pvid = bitfield_extract_by_mask(val, VSC9953_VLAN_CFG_VID_MASK);
349a2477924SCodrin Ciubotariu 
350a2477924SCodrin Ciubotariu 	return 0;
351a2477924SCodrin Ciubotariu }
352a2477924SCodrin Ciubotariu #endif
353a2477924SCodrin Ciubotariu 
3549de05987SCodrin Ciubotariu /* Set PVID for a VSC9953 port */
vsc9953_port_vlan_pvid_set(int port_no,int pvid)3559de05987SCodrin Ciubotariu static void vsc9953_port_vlan_pvid_set(int port_no, int pvid)
3569de05987SCodrin Ciubotariu {
3579de05987SCodrin Ciubotariu 	uint val;
3589de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
3599de05987SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
3609de05987SCodrin Ciubotariu 
3619de05987SCodrin Ciubotariu 	/* Administrative down */
3629de05987SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
3639de05987SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
3649de05987SCodrin Ciubotariu 		return;
3659de05987SCodrin Ciubotariu 	}
3669de05987SCodrin Ciubotariu 
3679de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
3689de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
3699de05987SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
3709de05987SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
3719de05987SCodrin Ciubotariu 
3729de05987SCodrin Ciubotariu 	/* Set PVID on ingress */
3739de05987SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_no].vlan_cfg);
3749de05987SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_VID_MASK, pvid);
3759de05987SCodrin Ciubotariu 	out_le32(&l2ana_reg->port[port_no].vlan_cfg, val);
3769de05987SCodrin Ciubotariu 
3779de05987SCodrin Ciubotariu 	/* Set PVID on egress */
3789de05987SCodrin Ciubotariu 	val = in_le32(&l2rew_reg->port[port_no].port_vlan_cfg);
3799de05987SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_PORT_VLAN_CFG_VID_MASK,
3809de05987SCodrin Ciubotariu 				       pvid);
3819de05987SCodrin Ciubotariu 	out_le32(&l2rew_reg->port[port_no].port_vlan_cfg, val);
3829de05987SCodrin Ciubotariu }
3839de05987SCodrin Ciubotariu 
vsc9953_port_all_vlan_pvid_set(int pvid)3849de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_pvid_set(int pvid)
3859de05987SCodrin Ciubotariu {
3869de05987SCodrin Ciubotariu 	int i;
3879de05987SCodrin Ciubotariu 
3889de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
3899de05987SCodrin Ciubotariu 		vsc9953_port_vlan_pvid_set(i, pvid);
3909de05987SCodrin Ciubotariu }
3919de05987SCodrin Ciubotariu 
3929de05987SCodrin Ciubotariu /* Enable/disable vlan aware of a VSC9953 port */
vsc9953_port_vlan_aware_set(int port_no,int enabled)3939de05987SCodrin Ciubotariu static void vsc9953_port_vlan_aware_set(int port_no, int enabled)
3949de05987SCodrin Ciubotariu {
3959de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
3969de05987SCodrin Ciubotariu 
3979de05987SCodrin Ciubotariu 	/* Administrative down */
3989de05987SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
3999de05987SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
4009de05987SCodrin Ciubotariu 		return;
4019de05987SCodrin Ciubotariu 	}
4029de05987SCodrin Ciubotariu 
4039de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
4049de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
4059de05987SCodrin Ciubotariu 
4069de05987SCodrin Ciubotariu 	if (enabled)
4079de05987SCodrin Ciubotariu 		setbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
4089de05987SCodrin Ciubotariu 			     VSC9953_VLAN_CFG_AWARE_ENA);
4099de05987SCodrin Ciubotariu 	else
4109de05987SCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
4119de05987SCodrin Ciubotariu 			     VSC9953_VLAN_CFG_AWARE_ENA);
4129de05987SCodrin Ciubotariu }
4139de05987SCodrin Ciubotariu 
4149de05987SCodrin Ciubotariu /* Set all VSC9953 ports' vlan aware  */
vsc9953_port_all_vlan_aware_set(int enabled)4159de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_aware_set(int enabled)
4169de05987SCodrin Ciubotariu {
4179de05987SCodrin Ciubotariu 	int i;
4189de05987SCodrin Ciubotariu 
4199de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
4209de05987SCodrin Ciubotariu 		vsc9953_port_vlan_aware_set(i, enabled);
4219de05987SCodrin Ciubotariu }
4229de05987SCodrin Ciubotariu 
4239de05987SCodrin Ciubotariu /* Enable/disable vlan pop count of a VSC9953 port */
vsc9953_port_vlan_popcnt_set(int port_no,int popcnt)4249de05987SCodrin Ciubotariu static void vsc9953_port_vlan_popcnt_set(int port_no, int popcnt)
4259de05987SCodrin Ciubotariu {
4269de05987SCodrin Ciubotariu 	uint val;
4279de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
4289de05987SCodrin Ciubotariu 
4299de05987SCodrin Ciubotariu 	/* Administrative down */
4309de05987SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
4319de05987SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
4329de05987SCodrin Ciubotariu 		return;
4339de05987SCodrin Ciubotariu 	}
4349de05987SCodrin Ciubotariu 
4359de05987SCodrin Ciubotariu 	if (popcnt > 3 || popcnt < 0) {
4369de05987SCodrin Ciubotariu 		printf("Invalid pop count value: %d\n", port_no);
4379de05987SCodrin Ciubotariu 		return;
4389de05987SCodrin Ciubotariu 	}
4399de05987SCodrin Ciubotariu 
4409de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
4419de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
4429de05987SCodrin Ciubotariu 
4439de05987SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_no].vlan_cfg);
4449de05987SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_POP_CNT_MASK,
4459de05987SCodrin Ciubotariu 				       popcnt);
4469de05987SCodrin Ciubotariu 	out_le32(&l2ana_reg->port[port_no].vlan_cfg, val);
4479de05987SCodrin Ciubotariu }
4489de05987SCodrin Ciubotariu 
4499de05987SCodrin Ciubotariu /* Set all VSC9953 ports' pop count  */
vsc9953_port_all_vlan_poncnt_set(int popcnt)4509de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_poncnt_set(int popcnt)
4519de05987SCodrin Ciubotariu {
4529de05987SCodrin Ciubotariu 	int i;
4539de05987SCodrin Ciubotariu 
4549de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
4559de05987SCodrin Ciubotariu 		vsc9953_port_vlan_popcnt_set(i, popcnt);
4569de05987SCodrin Ciubotariu }
4579de05987SCodrin Ciubotariu 
4589de05987SCodrin Ciubotariu /* Enable/disable learning for frames dropped due to ingress filtering */
vsc9953_vlan_ingr_fltr_learn_drop(int enable)4599de05987SCodrin Ciubotariu static void vsc9953_vlan_ingr_fltr_learn_drop(int enable)
4609de05987SCodrin Ciubotariu {
4619de05987SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
4629de05987SCodrin Ciubotariu 
4639de05987SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
4649de05987SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
4659de05987SCodrin Ciubotariu 
4669de05987SCodrin Ciubotariu 	if (enable)
4679de05987SCodrin Ciubotariu 		setbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
4689de05987SCodrin Ciubotariu 	else
4699de05987SCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
4709de05987SCodrin Ciubotariu }
4719de05987SCodrin Ciubotariu 
472aae0e689SCodrin Ciubotariu enum aggr_code_mode {
473aae0e689SCodrin Ciubotariu 	AGGR_CODE_RAND = 0,
474aae0e689SCodrin Ciubotariu 	AGGR_CODE_ALL,	/* S/D MAC, IPv4 S/D IP, IPv6 Flow Label, S/D PORT */
475aae0e689SCodrin Ciubotariu };
476aae0e689SCodrin Ciubotariu 
477aae0e689SCodrin Ciubotariu /* Set aggregation code generation mode */
vsc9953_aggr_code_set(enum aggr_code_mode ac)478aae0e689SCodrin Ciubotariu static int vsc9953_aggr_code_set(enum aggr_code_mode ac)
479aae0e689SCodrin Ciubotariu {
480aae0e689SCodrin Ciubotariu 	int rc;
481aae0e689SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
482aae0e689SCodrin Ciubotariu 
483aae0e689SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
484aae0e689SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
485aae0e689SCodrin Ciubotariu 
486aae0e689SCodrin Ciubotariu 	switch (ac) {
487aae0e689SCodrin Ciubotariu 	case AGGR_CODE_RAND:
488aae0e689SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->common.aggr_cfg,
489aae0e689SCodrin Ciubotariu 				VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
490aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP6_LBL_ENA |
491aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP6_TCPUDP_ENA |
492aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP4_SIPDIP_ENA |
493aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP4_TCPUDP_ENA, VSC9953_AC_RND_ENA);
494aae0e689SCodrin Ciubotariu 		rc = 0;
495aae0e689SCodrin Ciubotariu 		break;
496aae0e689SCodrin Ciubotariu 	case AGGR_CODE_ALL:
497aae0e689SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->common.aggr_cfg, VSC9953_AC_RND_ENA,
498aae0e689SCodrin Ciubotariu 				VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
499aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP6_LBL_ENA |
500aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP6_TCPUDP_ENA |
501aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP4_SIPDIP_ENA |
502aae0e689SCodrin Ciubotariu 				VSC9953_AC_IP4_TCPUDP_ENA);
503aae0e689SCodrin Ciubotariu 		rc = 0;
504aae0e689SCodrin Ciubotariu 		break;
505aae0e689SCodrin Ciubotariu 	default:
506aae0e689SCodrin Ciubotariu 		/* unknown mode for aggregation code */
507aae0e689SCodrin Ciubotariu 		rc = -EINVAL;
508aae0e689SCodrin Ciubotariu 	}
509aae0e689SCodrin Ciubotariu 
510aae0e689SCodrin Ciubotariu 	return rc;
511aae0e689SCodrin Ciubotariu }
512aae0e689SCodrin Ciubotariu 
5139de05987SCodrin Ciubotariu /* Egress untag modes of a VSC9953 port */
5149de05987SCodrin Ciubotariu enum egress_untag_mode {
5159de05987SCodrin Ciubotariu 	EGRESS_UNTAG_ALL = 0,
5169de05987SCodrin Ciubotariu 	EGRESS_UNTAG_PVID_AND_ZERO,
5179de05987SCodrin Ciubotariu 	EGRESS_UNTAG_ZERO,
5189de05987SCodrin Ciubotariu 	EGRESS_UNTAG_NONE,
5199de05987SCodrin Ciubotariu };
5209de05987SCodrin Ciubotariu 
521a2477924SCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
522a2477924SCodrin Ciubotariu /* Get egress tagging configuration for a VSC9953 port */
vsc9953_port_vlan_egr_untag_get(int port_no,enum egress_untag_mode * mode)523a2477924SCodrin Ciubotariu static int vsc9953_port_vlan_egr_untag_get(int port_no,
524a2477924SCodrin Ciubotariu 					   enum egress_untag_mode *mode)
525a2477924SCodrin Ciubotariu {
526a2477924SCodrin Ciubotariu 	u32 val;
527a2477924SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
528a2477924SCodrin Ciubotariu 
529a2477924SCodrin Ciubotariu 	/* Administrative down */
530a2477924SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
531a2477924SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
532a2477924SCodrin Ciubotariu 		return -1;
533a2477924SCodrin Ciubotariu 	}
534a2477924SCodrin Ciubotariu 
535a2477924SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
536a2477924SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
537a2477924SCodrin Ciubotariu 
538a2477924SCodrin Ciubotariu 	val = in_le32(&l2rew_reg->port[port_no].port_tag_cfg);
539a2477924SCodrin Ciubotariu 
540a2477924SCodrin Ciubotariu 	switch (val & VSC9953_TAG_CFG_MASK) {
541a2477924SCodrin Ciubotariu 	case VSC9953_TAG_CFG_NONE:
542a2477924SCodrin Ciubotariu 		*mode = EGRESS_UNTAG_ALL;
543a2477924SCodrin Ciubotariu 		return 0;
544a2477924SCodrin Ciubotariu 	case VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO:
545a2477924SCodrin Ciubotariu 		*mode = EGRESS_UNTAG_PVID_AND_ZERO;
546a2477924SCodrin Ciubotariu 		return 0;
547a2477924SCodrin Ciubotariu 	case VSC9953_TAG_CFG_ALL_BUT_ZERO:
548a2477924SCodrin Ciubotariu 		*mode = EGRESS_UNTAG_ZERO;
549a2477924SCodrin Ciubotariu 		return 0;
550a2477924SCodrin Ciubotariu 	case VSC9953_TAG_CFG_ALL:
551a2477924SCodrin Ciubotariu 		*mode = EGRESS_UNTAG_NONE;
552a2477924SCodrin Ciubotariu 		return 0;
553a2477924SCodrin Ciubotariu 	default:
554a2477924SCodrin Ciubotariu 		printf("Unknown egress tagging configuration for port %d\n",
555a2477924SCodrin Ciubotariu 		       port_no);
556a2477924SCodrin Ciubotariu 		return -1;
557a2477924SCodrin Ciubotariu 	}
558a2477924SCodrin Ciubotariu }
559a2477924SCodrin Ciubotariu 
560a2477924SCodrin Ciubotariu /* Show egress tagging configuration for a VSC9953 port */
vsc9953_port_vlan_egr_untag_show(int port_no)561a2477924SCodrin Ciubotariu static void vsc9953_port_vlan_egr_untag_show(int port_no)
562a2477924SCodrin Ciubotariu {
563a2477924SCodrin Ciubotariu 	enum egress_untag_mode mode;
564a2477924SCodrin Ciubotariu 
565a2477924SCodrin Ciubotariu 	if (vsc9953_port_vlan_egr_untag_get(port_no, &mode)) {
566a2477924SCodrin Ciubotariu 		printf("%7d\t%17s\n", port_no, "-");
567a2477924SCodrin Ciubotariu 		return;
568a2477924SCodrin Ciubotariu 	}
569a2477924SCodrin Ciubotariu 
570a2477924SCodrin Ciubotariu 	printf("%7d\t", port_no);
571a2477924SCodrin Ciubotariu 	switch (mode) {
572a2477924SCodrin Ciubotariu 	case EGRESS_UNTAG_ALL:
573a2477924SCodrin Ciubotariu 		printf("%17s\n", "all");
574a2477924SCodrin Ciubotariu 		break;
575a2477924SCodrin Ciubotariu 	case EGRESS_UNTAG_NONE:
576a2477924SCodrin Ciubotariu 		printf("%17s\n", "none");
577a2477924SCodrin Ciubotariu 		break;
578a2477924SCodrin Ciubotariu 	case EGRESS_UNTAG_PVID_AND_ZERO:
579a2477924SCodrin Ciubotariu 		printf("%17s\n", "PVID and 0");
580a2477924SCodrin Ciubotariu 		break;
581a2477924SCodrin Ciubotariu 	case EGRESS_UNTAG_ZERO:
582a2477924SCodrin Ciubotariu 		printf("%17s\n", "0");
583a2477924SCodrin Ciubotariu 		break;
584a2477924SCodrin Ciubotariu 	default:
585a2477924SCodrin Ciubotariu 		printf("%17s\n", "-");
586a2477924SCodrin Ciubotariu 	}
587a2477924SCodrin Ciubotariu }
588a2477924SCodrin Ciubotariu #endif
589a2477924SCodrin Ciubotariu 
vsc9953_port_vlan_egr_untag_set(int port_no,enum egress_untag_mode mode)5909de05987SCodrin Ciubotariu static void vsc9953_port_vlan_egr_untag_set(int port_no,
5919de05987SCodrin Ciubotariu 					    enum egress_untag_mode mode)
5929de05987SCodrin Ciubotariu {
5939de05987SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
5949de05987SCodrin Ciubotariu 
5959de05987SCodrin Ciubotariu 	/* Administrative down */
5969de05987SCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
5979de05987SCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
5989de05987SCodrin Ciubotariu 		return;
5999de05987SCodrin Ciubotariu 	}
6009de05987SCodrin Ciubotariu 
6019de05987SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
6029de05987SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
6039de05987SCodrin Ciubotariu 
6049de05987SCodrin Ciubotariu 	switch (mode) {
6059de05987SCodrin Ciubotariu 	case EGRESS_UNTAG_ALL:
6069de05987SCodrin Ciubotariu 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
6079de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_NONE);
6089de05987SCodrin Ciubotariu 		break;
6099de05987SCodrin Ciubotariu 	case EGRESS_UNTAG_PVID_AND_ZERO:
6109de05987SCodrin Ciubotariu 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
6119de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_MASK,
6129de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO);
6139de05987SCodrin Ciubotariu 		break;
6149de05987SCodrin Ciubotariu 	case EGRESS_UNTAG_ZERO:
6159de05987SCodrin Ciubotariu 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
6169de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_MASK,
6179de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_ALL_BUT_ZERO);
6189de05987SCodrin Ciubotariu 		break;
6199de05987SCodrin Ciubotariu 	case EGRESS_UNTAG_NONE:
6209de05987SCodrin Ciubotariu 		clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
6219de05987SCodrin Ciubotariu 				VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_ALL);
6229de05987SCodrin Ciubotariu 		break;
6239de05987SCodrin Ciubotariu 	default:
6249de05987SCodrin Ciubotariu 		printf("Unknown untag mode for port %d\n", port_no);
6259de05987SCodrin Ciubotariu 	}
6269de05987SCodrin Ciubotariu }
6279de05987SCodrin Ciubotariu 
vsc9953_port_all_vlan_egress_untagged_set(enum egress_untag_mode mode)6289de05987SCodrin Ciubotariu static void vsc9953_port_all_vlan_egress_untagged_set(
6299de05987SCodrin Ciubotariu 		enum egress_untag_mode mode)
6309de05987SCodrin Ciubotariu {
6319de05987SCodrin Ciubotariu 	int i;
6329de05987SCodrin Ciubotariu 
6339de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++)
6349de05987SCodrin Ciubotariu 		vsc9953_port_vlan_egr_untag_set(i, mode);
6359de05987SCodrin Ciubotariu }
6369de05987SCodrin Ciubotariu 
vsc9953_autoage_time_set(int age_period)637ba389e65SCodrin Ciubotariu static int vsc9953_autoage_time_set(int age_period)
638ba389e65SCodrin Ciubotariu {
639ba389e65SCodrin Ciubotariu 	u32 autoage;
640ba389e65SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
641ba389e65SCodrin Ciubotariu 
642ba389e65SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
643ba389e65SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
644ba389e65SCodrin Ciubotariu 
645ba389e65SCodrin Ciubotariu 	if (age_period < 0 || age_period > VSC9953_AUTOAGE_PERIOD_MASK)
646ba389e65SCodrin Ciubotariu 		return -EINVAL;
647ba389e65SCodrin Ciubotariu 
648ba389e65SCodrin Ciubotariu 	autoage = bitfield_replace_by_mask(in_le32(&l2ana_reg->ana.auto_age),
649ba389e65SCodrin Ciubotariu 					   VSC9953_AUTOAGE_PERIOD_MASK,
650ba389e65SCodrin Ciubotariu 					   age_period);
651ba389e65SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana.auto_age, autoage);
652ba389e65SCodrin Ciubotariu 
653ba389e65SCodrin Ciubotariu 	return 0;
654ba389e65SCodrin Ciubotariu }
655ba389e65SCodrin Ciubotariu 
65624a23debSCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
65724a23debSCodrin Ciubotariu 
65824a23debSCodrin Ciubotariu /* Enable/disable status of a VSC9953 port */
vsc9953_port_status_set(int port_no,u8 enabled)65924a23debSCodrin Ciubotariu static void vsc9953_port_status_set(int port_no, u8 enabled)
66024a23debSCodrin Ciubotariu {
66124a23debSCodrin Ciubotariu 	struct vsc9953_qsys_reg *l2qsys_reg;
66224a23debSCodrin Ciubotariu 
66324a23debSCodrin Ciubotariu 	/* Administrative down */
66424a23debSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled)
66524a23debSCodrin Ciubotariu 		return;
66624a23debSCodrin Ciubotariu 
66724a23debSCodrin Ciubotariu 	l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
66824a23debSCodrin Ciubotariu 			VSC9953_QSYS_OFFSET);
66924a23debSCodrin Ciubotariu 
67024a23debSCodrin Ciubotariu 	if (enabled)
67124a23debSCodrin Ciubotariu 		setbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no],
67224a23debSCodrin Ciubotariu 			     VSC9953_PORT_ENA);
67324a23debSCodrin Ciubotariu 	else
67424a23debSCodrin Ciubotariu 		clrbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no],
67524a23debSCodrin Ciubotariu 			     VSC9953_PORT_ENA);
67624a23debSCodrin Ciubotariu }
67724a23debSCodrin Ciubotariu 
67824a23debSCodrin Ciubotariu /* Start autonegotiation for a VSC9953 PHY */
vsc9953_phy_autoneg(int port_no)67924a23debSCodrin Ciubotariu static void vsc9953_phy_autoneg(int port_no)
68024a23debSCodrin Ciubotariu {
68124a23debSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].phydev)
68224a23debSCodrin Ciubotariu 		return;
68324a23debSCodrin Ciubotariu 
68424a23debSCodrin Ciubotariu 	if (vsc9953_l2sw.port[port_no].phydev->drv->startup(
68524a23debSCodrin Ciubotariu 			vsc9953_l2sw.port[port_no].phydev))
68624a23debSCodrin Ciubotariu 		printf("Failed to start PHY for port %d\n", port_no);
68724a23debSCodrin Ciubotariu }
68824a23debSCodrin Ciubotariu 
68924a23debSCodrin Ciubotariu /* Print a VSC9953 port's configuration */
vsc9953_port_config_show(int port_no)69024a23debSCodrin Ciubotariu static void vsc9953_port_config_show(int port_no)
69124a23debSCodrin Ciubotariu {
69224a23debSCodrin Ciubotariu 	int speed;
69324a23debSCodrin Ciubotariu 	int duplex;
69424a23debSCodrin Ciubotariu 	int link;
69524a23debSCodrin Ciubotariu 	u8 enabled;
69624a23debSCodrin Ciubotariu 	u32 val;
69724a23debSCodrin Ciubotariu 	struct vsc9953_qsys_reg *l2qsys_reg;
69824a23debSCodrin Ciubotariu 
69924a23debSCodrin Ciubotariu 	l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
70024a23debSCodrin Ciubotariu 			VSC9953_QSYS_OFFSET);
70124a23debSCodrin Ciubotariu 
70224a23debSCodrin Ciubotariu 	val = in_le32(&l2qsys_reg->sys.switch_port_mode[port_no]);
70324a23debSCodrin Ciubotariu 	enabled = vsc9953_l2sw.port[port_no].enabled &&
70424a23debSCodrin Ciubotariu 		  (val & VSC9953_PORT_ENA);
70524a23debSCodrin Ciubotariu 
70624a23debSCodrin Ciubotariu 	/* internal ports (8 and 9) are fixed */
70724a23debSCodrin Ciubotariu 	if (VSC9953_INTERNAL_PORT_CHECK(port_no)) {
70824a23debSCodrin Ciubotariu 		link = 1;
70924a23debSCodrin Ciubotariu 		speed = SPEED_2500;
71024a23debSCodrin Ciubotariu 		duplex = DUPLEX_FULL;
71124a23debSCodrin Ciubotariu 	} else {
71224a23debSCodrin Ciubotariu 		if (vsc9953_l2sw.port[port_no].phydev) {
71324a23debSCodrin Ciubotariu 			link = vsc9953_l2sw.port[port_no].phydev->link;
71424a23debSCodrin Ciubotariu 			speed = vsc9953_l2sw.port[port_no].phydev->speed;
71524a23debSCodrin Ciubotariu 			duplex = vsc9953_l2sw.port[port_no].phydev->duplex;
71624a23debSCodrin Ciubotariu 		} else {
71724a23debSCodrin Ciubotariu 			link = -1;
71824a23debSCodrin Ciubotariu 			speed = -1;
71924a23debSCodrin Ciubotariu 			duplex = -1;
72024a23debSCodrin Ciubotariu 		}
72124a23debSCodrin Ciubotariu 	}
72224a23debSCodrin Ciubotariu 
72324a23debSCodrin Ciubotariu 	printf("%8d ", port_no);
72424a23debSCodrin Ciubotariu 	printf("%8s ", enabled == 1 ? "enabled" : "disabled");
72524a23debSCodrin Ciubotariu 	printf("%8s ", link == 1 ? "up" : "down");
72624a23debSCodrin Ciubotariu 
72724a23debSCodrin Ciubotariu 	switch (speed) {
72824a23debSCodrin Ciubotariu 	case SPEED_10:
72924a23debSCodrin Ciubotariu 		printf("%8d ", 10);
73024a23debSCodrin Ciubotariu 		break;
73124a23debSCodrin Ciubotariu 	case SPEED_100:
73224a23debSCodrin Ciubotariu 		printf("%8d ", 100);
73324a23debSCodrin Ciubotariu 		break;
73424a23debSCodrin Ciubotariu 	case SPEED_1000:
73524a23debSCodrin Ciubotariu 		printf("%8d ", 1000);
73624a23debSCodrin Ciubotariu 		break;
73724a23debSCodrin Ciubotariu 	case SPEED_2500:
73824a23debSCodrin Ciubotariu 		printf("%8d ", 2500);
73924a23debSCodrin Ciubotariu 		break;
74024a23debSCodrin Ciubotariu 	case SPEED_10000:
74124a23debSCodrin Ciubotariu 		printf("%8d ", 10000);
74224a23debSCodrin Ciubotariu 		break;
74324a23debSCodrin Ciubotariu 	default:
74424a23debSCodrin Ciubotariu 		printf("%8s ", "-");
74524a23debSCodrin Ciubotariu 	}
74624a23debSCodrin Ciubotariu 
74724a23debSCodrin Ciubotariu 	printf("%8s\n", duplex == DUPLEX_FULL ? "full" : "half");
74824a23debSCodrin Ciubotariu }
74924a23debSCodrin Ciubotariu 
75086719f0cSCodrin Ciubotariu /* Show VSC9953 ports' statistics */
vsc9953_port_statistics_show(int port_no)75186719f0cSCodrin Ciubotariu static void vsc9953_port_statistics_show(int port_no)
75286719f0cSCodrin Ciubotariu {
75386719f0cSCodrin Ciubotariu 	u32 rx_val;
75486719f0cSCodrin Ciubotariu 	u32 tx_val;
75586719f0cSCodrin Ciubotariu 	struct vsc9953_system_reg *l2sys_reg;
75686719f0cSCodrin Ciubotariu 
75786719f0cSCodrin Ciubotariu 	/* Administrative down */
75886719f0cSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
75986719f0cSCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
76086719f0cSCodrin Ciubotariu 		return;
76186719f0cSCodrin Ciubotariu 	}
76286719f0cSCodrin Ciubotariu 
76386719f0cSCodrin Ciubotariu 	l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET +
76486719f0cSCodrin Ciubotariu 			VSC9953_SYS_OFFSET);
76586719f0cSCodrin Ciubotariu 
76686719f0cSCodrin Ciubotariu 	printf("Statistics for L2 Switch port %d:\n", port_no);
76786719f0cSCodrin Ciubotariu 
76886719f0cSCodrin Ciubotariu 	/* Set counter view for our port */
76986719f0cSCodrin Ciubotariu 	out_le32(&l2sys_reg->sys.stat_cfg, port_no);
77086719f0cSCodrin Ciubotariu 
77186719f0cSCodrin Ciubotariu #define VSC9953_STATS_PRINTF "%-15s %10u"
77286719f0cSCodrin Ciubotariu 
77386719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames */
77486719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_short) +
77586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_frag) +
77686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_jabber) +
77786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_long) +
77886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_64) +
77986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_65_127) +
78086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_128_255) +
78186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_256_511) +
78286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_512_1023) +
78386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_1024_1526) +
78486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_jumbo);
78586719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64) +
78686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127) +
78786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255) +
78886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511) +
78986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023) +
79086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526) +
79186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo);
79286719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
79386719f0cSCodrin Ciubotariu 	       "Rx frames:", rx_val, "Tx frames:", tx_val);
79486719f0cSCodrin Ciubotariu 
79586719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx bytes */
79686719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_oct);
79786719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_oct);
79886719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
79986719f0cSCodrin Ciubotariu 	       "Rx bytes:", rx_val, "Tx bytes:", tx_val);
80086719f0cSCodrin Ciubotariu 
80186719f0cSCodrin Ciubotariu 	/* Get number of Rx frames received ok and Tx frames sent ok */
80286719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_0) +
80386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_1) +
80486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_2) +
80586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_3) +
80686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_4) +
80786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_5) +
80886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_6) +
80986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_7) +
81086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_0) +
81186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_1) +
81286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_2) +
81386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_3) +
81486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_4) +
81586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_5) +
81686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_6) +
81786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_7);
81886719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64) +
81986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127) +
82086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255) +
82186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511) +
82286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023) +
82386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526) +
82486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo);
82586719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
82686719f0cSCodrin Ciubotariu 	       "Rx frames ok:", rx_val, "Tx frames ok:", tx_val);
82786719f0cSCodrin Ciubotariu 
82886719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx unicast frames */
82986719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_uc);
83086719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_uc);
83186719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
83286719f0cSCodrin Ciubotariu 	       "Rx unicast:", rx_val, "Tx unicast:", tx_val);
83386719f0cSCodrin Ciubotariu 
83486719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx broadcast frames */
83586719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_bc);
83686719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_bc);
83786719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
83886719f0cSCodrin Ciubotariu 	       "Rx broadcast:", rx_val, "Tx broadcast:", tx_val);
83986719f0cSCodrin Ciubotariu 
84086719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames of 64B */
84186719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_64);
84286719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64);
84386719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
84486719f0cSCodrin Ciubotariu 	       "Rx 64B:", rx_val, "Tx 64B:", tx_val);
84586719f0cSCodrin Ciubotariu 
84686719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 65B and 127B */
84786719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_65_127);
84886719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127);
84986719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
85086719f0cSCodrin Ciubotariu 	       "Rx 65B-127B:", rx_val, "Tx 65B-127B:", tx_val);
85186719f0cSCodrin Ciubotariu 
85286719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 128B and 255B */
85386719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_128_255);
85486719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255);
85586719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
85686719f0cSCodrin Ciubotariu 	       "Rx 128B-255B:", rx_val, "Tx 128B-255B:", tx_val);
85786719f0cSCodrin Ciubotariu 
85886719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 256B and 511B */
85986719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_256_511);
86086719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511);
86186719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
86286719f0cSCodrin Ciubotariu 	       "Rx 256B-511B:", rx_val, "Tx 256B-511B:", tx_val);
86386719f0cSCodrin Ciubotariu 
86486719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 512B and 1023B */
86586719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_512_1023);
86686719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023);
86786719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
86886719f0cSCodrin Ciubotariu 	       "Rx 512B-1023B:", rx_val, "Tx 512B-1023B:", tx_val);
86986719f0cSCodrin Ciubotariu 
87086719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx frames with sizes between 1024B and 1526B */
87186719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_1024_1526);
87286719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526);
87386719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
87486719f0cSCodrin Ciubotariu 	       "Rx 1024B-1526B:", rx_val, "Tx 1024B-1526B:", tx_val);
87586719f0cSCodrin Ciubotariu 
87686719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx jumbo frames */
87786719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_jumbo);
87886719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo);
87986719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
88086719f0cSCodrin Ciubotariu 	       "Rx jumbo:", rx_val, "Tx jumbo:", tx_val);
88186719f0cSCodrin Ciubotariu 
88286719f0cSCodrin Ciubotariu 	/* Get number of Rx and Tx dropped frames */
88386719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_cat_drop) +
88486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_tail) +
88586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_0) +
88686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_1) +
88786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_2) +
88886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_3) +
88986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_4) +
89086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_5) +
89186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_6) +
89286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_7) +
89386719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_0) +
89486719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_1) +
89586719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_2) +
89686719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_3) +
89786719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_4) +
89886719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_5) +
89986719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_6) +
90086719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_7);
90186719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_drop) +
90286719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_aged);
90386719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
90486719f0cSCodrin Ciubotariu 	       "Rx drops:", rx_val, "Tx drops:", tx_val);
90586719f0cSCodrin Ciubotariu 
90686719f0cSCodrin Ciubotariu 	/*
90786719f0cSCodrin Ciubotariu 	 * Get number of Rx frames with CRC or alignment errors
90886719f0cSCodrin Ciubotariu 	 * and number of detected Tx collisions
90986719f0cSCodrin Ciubotariu 	 */
91086719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_crc);
91186719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_col);
91286719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
91386719f0cSCodrin Ciubotariu 	       "Rx CRC&align:", rx_val, "Tx coll:", tx_val);
91486719f0cSCodrin Ciubotariu 
91586719f0cSCodrin Ciubotariu 	/*
91686719f0cSCodrin Ciubotariu 	 * Get number of Rx undersized frames and
91786719f0cSCodrin Ciubotariu 	 * number of Tx aged frames
91886719f0cSCodrin Ciubotariu 	 */
91986719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_short);
92086719f0cSCodrin Ciubotariu 	tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_aged);
92186719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n",
92286719f0cSCodrin Ciubotariu 	       "Rx undersize:", rx_val, "Tx aged:", tx_val);
92386719f0cSCodrin Ciubotariu 
92486719f0cSCodrin Ciubotariu 	/* Get number of Rx oversized frames */
92586719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_long);
92686719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\n", "Rx oversized:", rx_val);
92786719f0cSCodrin Ciubotariu 
92886719f0cSCodrin Ciubotariu 	/* Get number of Rx fragmented frames */
92986719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_frag);
93086719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\n", "Rx fragments:", rx_val);
93186719f0cSCodrin Ciubotariu 
93286719f0cSCodrin Ciubotariu 	/* Get number of Rx jabber errors */
93386719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_jabber);
93486719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\n", "Rx jabbers:", rx_val);
93586719f0cSCodrin Ciubotariu 
93686719f0cSCodrin Ciubotariu 	/*
93786719f0cSCodrin Ciubotariu 	 * Get number of Rx frames filtered due to classification rules or
93886719f0cSCodrin Ciubotariu 	 * no destination ports
93986719f0cSCodrin Ciubotariu 	 */
94086719f0cSCodrin Ciubotariu 	rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_cat_drop) +
94186719f0cSCodrin Ciubotariu 		 in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_local);
94286719f0cSCodrin Ciubotariu 	printf(VSC9953_STATS_PRINTF"\n", "Rx filtered:", rx_val);
94386719f0cSCodrin Ciubotariu 
94486719f0cSCodrin Ciubotariu 	printf("\n");
94586719f0cSCodrin Ciubotariu }
94686719f0cSCodrin Ciubotariu 
94786719f0cSCodrin Ciubotariu /* Clear statistics for a VSC9953 port */
vsc9953_port_statistics_clear(int port_no)94886719f0cSCodrin Ciubotariu static void vsc9953_port_statistics_clear(int port_no)
94986719f0cSCodrin Ciubotariu {
95086719f0cSCodrin Ciubotariu 	struct vsc9953_system_reg *l2sys_reg;
95186719f0cSCodrin Ciubotariu 
95286719f0cSCodrin Ciubotariu 	/* Administrative down */
95386719f0cSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
95486719f0cSCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
95586719f0cSCodrin Ciubotariu 		return;
95686719f0cSCodrin Ciubotariu 	}
95786719f0cSCodrin Ciubotariu 
95886719f0cSCodrin Ciubotariu 	l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET +
95986719f0cSCodrin Ciubotariu 			VSC9953_SYS_OFFSET);
96086719f0cSCodrin Ciubotariu 
96186719f0cSCodrin Ciubotariu 	/* Clear all counter groups for our ports */
96286719f0cSCodrin Ciubotariu 	out_le32(&l2sys_reg->sys.stat_cfg, port_no |
96386719f0cSCodrin Ciubotariu 		 VSC9953_STAT_CLEAR_RX | VSC9953_STAT_CLEAR_TX |
96486719f0cSCodrin Ciubotariu 		 VSC9953_STAT_CLEAR_DR);
96586719f0cSCodrin Ciubotariu }
96686719f0cSCodrin Ciubotariu 
96768c929daSCodrin Ciubotariu enum port_learn_mode {
96868c929daSCodrin Ciubotariu 	PORT_LEARN_NONE,
96968c929daSCodrin Ciubotariu 	PORT_LEARN_AUTO
97068c929daSCodrin Ciubotariu };
97168c929daSCodrin Ciubotariu 
97268c929daSCodrin Ciubotariu /* Set learning configuration for a VSC9953 port */
vsc9953_port_learn_mode_set(int port_no,enum port_learn_mode mode)97368c929daSCodrin Ciubotariu static void vsc9953_port_learn_mode_set(int port_no, enum port_learn_mode mode)
97468c929daSCodrin Ciubotariu {
97568c929daSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
97668c929daSCodrin Ciubotariu 
97768c929daSCodrin Ciubotariu 	/* Administrative down */
97868c929daSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
97968c929daSCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
98068c929daSCodrin Ciubotariu 		return;
98168c929daSCodrin Ciubotariu 	}
98268c929daSCodrin Ciubotariu 
98368c929daSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
98468c929daSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
98568c929daSCodrin Ciubotariu 
98668c929daSCodrin Ciubotariu 	switch (mode) {
98768c929daSCodrin Ciubotariu 	case PORT_LEARN_NONE:
98868c929daSCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->port[port_no].port_cfg,
98968c929daSCodrin Ciubotariu 			     VSC9953_PORT_CFG_LEARN_DROP |
99068c929daSCodrin Ciubotariu 			     VSC9953_PORT_CFG_LEARN_CPU |
99168c929daSCodrin Ciubotariu 			     VSC9953_PORT_CFG_LEARN_AUTO |
99268c929daSCodrin Ciubotariu 			     VSC9953_PORT_CFG_LEARN_ENA);
99368c929daSCodrin Ciubotariu 		break;
99468c929daSCodrin Ciubotariu 	case PORT_LEARN_AUTO:
99568c929daSCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->port[port_no].port_cfg,
99668c929daSCodrin Ciubotariu 				VSC9953_PORT_CFG_LEARN_DROP |
99768c929daSCodrin Ciubotariu 				VSC9953_PORT_CFG_LEARN_CPU,
99868c929daSCodrin Ciubotariu 				VSC9953_PORT_CFG_LEARN_ENA |
99968c929daSCodrin Ciubotariu 				VSC9953_PORT_CFG_LEARN_AUTO);
100068c929daSCodrin Ciubotariu 		break;
100168c929daSCodrin Ciubotariu 	default:
100268c929daSCodrin Ciubotariu 		printf("Unknown learn mode for port %d\n", port_no);
100368c929daSCodrin Ciubotariu 	}
100468c929daSCodrin Ciubotariu }
100568c929daSCodrin Ciubotariu 
100668c929daSCodrin Ciubotariu /* Get learning configuration for a VSC9953 port */
vsc9953_port_learn_mode_get(int port_no,enum port_learn_mode * mode)100768c929daSCodrin Ciubotariu static int vsc9953_port_learn_mode_get(int port_no, enum port_learn_mode *mode)
100868c929daSCodrin Ciubotariu {
100968c929daSCodrin Ciubotariu 	u32 val;
101068c929daSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
101168c929daSCodrin Ciubotariu 
101268c929daSCodrin Ciubotariu 	/* Administrative down */
101368c929daSCodrin Ciubotariu 	if (!vsc9953_l2sw.port[port_no].enabled) {
101468c929daSCodrin Ciubotariu 		printf("Port %d is administrative down\n", port_no);
101568c929daSCodrin Ciubotariu 		return -1;
101668c929daSCodrin Ciubotariu 	}
101768c929daSCodrin Ciubotariu 
101868c929daSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
101968c929daSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
102068c929daSCodrin Ciubotariu 
102168c929daSCodrin Ciubotariu 	/* For now we only support HW learning (auto) and no learning */
102268c929daSCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_no].port_cfg);
102368c929daSCodrin Ciubotariu 	if ((val & (VSC9953_PORT_CFG_LEARN_ENA |
102468c929daSCodrin Ciubotariu 		    VSC9953_PORT_CFG_LEARN_AUTO)) ==
102568c929daSCodrin Ciubotariu 	    (VSC9953_PORT_CFG_LEARN_ENA | VSC9953_PORT_CFG_LEARN_AUTO))
102668c929daSCodrin Ciubotariu 		*mode = PORT_LEARN_AUTO;
102768c929daSCodrin Ciubotariu 	else
102868c929daSCodrin Ciubotariu 		*mode = PORT_LEARN_NONE;
102968c929daSCodrin Ciubotariu 
103068c929daSCodrin Ciubotariu 	return 0;
103168c929daSCodrin Ciubotariu }
103268c929daSCodrin Ciubotariu 
103322449858SCodrin Ciubotariu /* wait for FDB to become available */
vsc9953_mac_table_poll_idle(void)103422449858SCodrin Ciubotariu static int vsc9953_mac_table_poll_idle(void)
103522449858SCodrin Ciubotariu {
103622449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
103722449858SCodrin Ciubotariu 	u32 timeout;
103822449858SCodrin Ciubotariu 
103922449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
104022449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
104122449858SCodrin Ciubotariu 
104222449858SCodrin Ciubotariu 	timeout = 50000;
104322449858SCodrin Ciubotariu 	while (((in_le32(&l2ana_reg->ana_tables.mac_access) &
104422449858SCodrin Ciubotariu 			 VSC9953_MAC_CMD_MASK) !=
104522449858SCodrin Ciubotariu 		VSC9953_MAC_CMD_IDLE) && --timeout)
104622449858SCodrin Ciubotariu 		udelay(1);
104722449858SCodrin Ciubotariu 
104822449858SCodrin Ciubotariu 	return timeout ? 0 : -EBUSY;
104922449858SCodrin Ciubotariu }
105022449858SCodrin Ciubotariu 
105122449858SCodrin Ciubotariu /* enum describing available commands for the MAC table */
105222449858SCodrin Ciubotariu enum mac_table_cmd {
105322449858SCodrin Ciubotariu 	MAC_TABLE_READ,
105422449858SCodrin Ciubotariu 	MAC_TABLE_LOOKUP,
105522449858SCodrin Ciubotariu 	MAC_TABLE_WRITE,
105622449858SCodrin Ciubotariu 	MAC_TABLE_LEARN,
105722449858SCodrin Ciubotariu 	MAC_TABLE_FORGET,
105822449858SCodrin Ciubotariu 	MAC_TABLE_GET_NEXT,
105922449858SCodrin Ciubotariu 	MAC_TABLE_AGE,
106022449858SCodrin Ciubotariu };
106122449858SCodrin Ciubotariu 
106222449858SCodrin Ciubotariu /* Issues a command to the FDB table */
vsc9953_mac_table_cmd(enum mac_table_cmd cmd)106322449858SCodrin Ciubotariu static int vsc9953_mac_table_cmd(enum mac_table_cmd cmd)
106422449858SCodrin Ciubotariu {
106522449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
106622449858SCodrin Ciubotariu 
106722449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
106822449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
106922449858SCodrin Ciubotariu 
107022449858SCodrin Ciubotariu 	switch (cmd) {
107122449858SCodrin Ciubotariu 	case MAC_TABLE_READ:
107222449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
107322449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK | VSC9953_MAC_CMD_VALID,
107422449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_READ);
107522449858SCodrin Ciubotariu 		break;
107622449858SCodrin Ciubotariu 	case MAC_TABLE_LOOKUP:
107722449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
107822449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK, VSC9953_MAC_CMD_READ |
107922449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_VALID);
108022449858SCodrin Ciubotariu 		break;
108122449858SCodrin Ciubotariu 	case MAC_TABLE_WRITE:
108222449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
108322449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
108422449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
108522449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_WRITE |
108622449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_LOCKED);
108722449858SCodrin Ciubotariu 		break;
108822449858SCodrin Ciubotariu 	case MAC_TABLE_LEARN:
108922449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
109022449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
109122449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
109222449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_LEARN |
109322449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_LOCKED |
109422449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_VALID);
109522449858SCodrin Ciubotariu 		break;
109622449858SCodrin Ciubotariu 	case MAC_TABLE_FORGET:
109722449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
109822449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
109922449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
110022449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_FORGET);
110122449858SCodrin Ciubotariu 		break;
110222449858SCodrin Ciubotariu 	case MAC_TABLE_GET_NEXT:
110322449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
110422449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
110522449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
110622449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_NEXT);
110722449858SCodrin Ciubotariu 		break;
110822449858SCodrin Ciubotariu 	case MAC_TABLE_AGE:
110922449858SCodrin Ciubotariu 		clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
111022449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_MASK |
111122449858SCodrin Ciubotariu 				VSC9953_MAC_ENTRYTYPE_MASK,
111222449858SCodrin Ciubotariu 				VSC9953_MAC_CMD_AGE);
111322449858SCodrin Ciubotariu 		break;
111422449858SCodrin Ciubotariu 	default:
111522449858SCodrin Ciubotariu 		printf("Unknown MAC table command\n");
111622449858SCodrin Ciubotariu 	}
111722449858SCodrin Ciubotariu 
111822449858SCodrin Ciubotariu 	if (vsc9953_mac_table_poll_idle() < 0) {
111922449858SCodrin Ciubotariu 		debug("MAC table timeout\n");
112022449858SCodrin Ciubotariu 		return -1;
112122449858SCodrin Ciubotariu 	}
112222449858SCodrin Ciubotariu 
112322449858SCodrin Ciubotariu 	return 0;
112422449858SCodrin Ciubotariu }
112522449858SCodrin Ciubotariu 
112622449858SCodrin Ciubotariu /* show the FDB entries that correspond to a port and a VLAN */
vsc9953_mac_table_show(int port_no,int vid)112722449858SCodrin Ciubotariu static void vsc9953_mac_table_show(int port_no, int vid)
112822449858SCodrin Ciubotariu {
112922449858SCodrin Ciubotariu 	int rc[VSC9953_MAX_PORTS];
113022449858SCodrin Ciubotariu 	enum port_learn_mode mode[VSC9953_MAX_PORTS];
113122449858SCodrin Ciubotariu 	int i;
113222449858SCodrin Ciubotariu 	u32 val;
113322449858SCodrin Ciubotariu 	u32 vlan;
113422449858SCodrin Ciubotariu 	u32 mach;
113522449858SCodrin Ciubotariu 	u32 macl;
113622449858SCodrin Ciubotariu 	u32 dest_indx;
113722449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
113822449858SCodrin Ciubotariu 
113922449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
114022449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
114122449858SCodrin Ciubotariu 
114222449858SCodrin Ciubotariu 	/* disable auto learning */
114322449858SCodrin Ciubotariu 	if (port_no == ETHSW_CMD_PORT_ALL) {
114422449858SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
114522449858SCodrin Ciubotariu 			rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]);
114622449858SCodrin Ciubotariu 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
114722449858SCodrin Ciubotariu 				vsc9953_port_learn_mode_set(i, PORT_LEARN_NONE);
114822449858SCodrin Ciubotariu 		}
114922449858SCodrin Ciubotariu 	} else {
115022449858SCodrin Ciubotariu 		rc[port_no] = vsc9953_port_learn_mode_get(port_no,
115122449858SCodrin Ciubotariu 							  &mode[port_no]);
115222449858SCodrin Ciubotariu 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
115322449858SCodrin Ciubotariu 			vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE);
115422449858SCodrin Ciubotariu 	}
115522449858SCodrin Ciubotariu 
115622449858SCodrin Ciubotariu 	/* write port and vid to get selected FDB entries */
115722449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana.anag_efil);
115822449858SCodrin Ciubotariu 	if (port_no != ETHSW_CMD_PORT_ALL) {
115922449858SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_AGE_PORT_MASK,
116022449858SCodrin Ciubotariu 					       port_no) | VSC9953_AGE_PORT_EN;
116122449858SCodrin Ciubotariu 	}
116222449858SCodrin Ciubotariu 	if (vid != ETHSW_CMD_VLAN_ALL) {
116322449858SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_AGE_VID_MASK,
116422449858SCodrin Ciubotariu 					       vid) | VSC9953_AGE_VID_EN;
116522449858SCodrin Ciubotariu 	}
116622449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana.anag_efil, val);
116722449858SCodrin Ciubotariu 
116822449858SCodrin Ciubotariu 	/* set MAC and VLAN to 0 to look from beginning */
116922449858SCodrin Ciubotariu 	clrbits_le32(&l2ana_reg->ana_tables.mach_data,
117022449858SCodrin Ciubotariu 		     VSC9953_MAC_VID_MASK | VSC9953_MAC_MACH_MASK);
117122449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data, 0);
117222449858SCodrin Ciubotariu 
117322449858SCodrin Ciubotariu 	/* get entries */
117422449858SCodrin Ciubotariu 	printf("%10s %17s %5s %4s\n", "EntryType", "MAC", "PORT", "VID");
117522449858SCodrin Ciubotariu 	do {
117622449858SCodrin Ciubotariu 		if (vsc9953_mac_table_cmd(MAC_TABLE_GET_NEXT) < 0) {
117722449858SCodrin Ciubotariu 			debug("GET NEXT MAC table command failed\n");
117822449858SCodrin Ciubotariu 			break;
117922449858SCodrin Ciubotariu 		}
118022449858SCodrin Ciubotariu 
118122449858SCodrin Ciubotariu 		val = in_le32(&l2ana_reg->ana_tables.mac_access);
118222449858SCodrin Ciubotariu 
118322449858SCodrin Ciubotariu 		/* get out when an invalid entry is found */
118422449858SCodrin Ciubotariu 		if (!(val & VSC9953_MAC_CMD_VALID))
118522449858SCodrin Ciubotariu 			break;
118622449858SCodrin Ciubotariu 
118722449858SCodrin Ciubotariu 		switch (val & VSC9953_MAC_ENTRYTYPE_MASK) {
118822449858SCodrin Ciubotariu 		case VSC9953_MAC_ENTRYTYPE_NORMAL:
118922449858SCodrin Ciubotariu 			printf("%10s ", "Dynamic");
119022449858SCodrin Ciubotariu 			break;
119122449858SCodrin Ciubotariu 		case VSC9953_MAC_ENTRYTYPE_LOCKED:
119222449858SCodrin Ciubotariu 			printf("%10s ", "Static");
119322449858SCodrin Ciubotariu 			break;
119422449858SCodrin Ciubotariu 		case VSC9953_MAC_ENTRYTYPE_IPV4MCAST:
119522449858SCodrin Ciubotariu 			printf("%10s ", "IPv4 Mcast");
119622449858SCodrin Ciubotariu 			break;
119722449858SCodrin Ciubotariu 		case VSC9953_MAC_ENTRYTYPE_IPV6MCAST:
119822449858SCodrin Ciubotariu 			printf("%10s ", "IPv6 Mcast");
119922449858SCodrin Ciubotariu 			break;
120022449858SCodrin Ciubotariu 		default:
120122449858SCodrin Ciubotariu 			printf("%10s ", "Unknown");
120222449858SCodrin Ciubotariu 		}
120322449858SCodrin Ciubotariu 
120422449858SCodrin Ciubotariu 		dest_indx = bitfield_extract_by_mask(val,
120522449858SCodrin Ciubotariu 						     VSC9953_MAC_DESTIDX_MASK);
120622449858SCodrin Ciubotariu 
120722449858SCodrin Ciubotariu 		val = in_le32(&l2ana_reg->ana_tables.mach_data);
120822449858SCodrin Ciubotariu 		vlan = bitfield_extract_by_mask(val, VSC9953_MAC_VID_MASK);
120922449858SCodrin Ciubotariu 		mach = bitfield_extract_by_mask(val, VSC9953_MAC_MACH_MASK);
121022449858SCodrin Ciubotariu 		macl = in_le32(&l2ana_reg->ana_tables.macl_data);
121122449858SCodrin Ciubotariu 
121222449858SCodrin Ciubotariu 		printf("%02x:%02x:%02x:%02x:%02x:%02x ", (mach >> 8) & 0xff,
121322449858SCodrin Ciubotariu 		       mach & 0xff, (macl >> 24) & 0xff, (macl >> 16) & 0xff,
121422449858SCodrin Ciubotariu 		       (macl >> 8) & 0xff, macl & 0xff);
121522449858SCodrin Ciubotariu 		printf("%5d ", dest_indx);
121622449858SCodrin Ciubotariu 		printf("%4d\n", vlan);
121722449858SCodrin Ciubotariu 	} while (1);
121822449858SCodrin Ciubotariu 
121922449858SCodrin Ciubotariu 	/* set learning mode to previous value */
122022449858SCodrin Ciubotariu 	if (port_no == ETHSW_CMD_PORT_ALL) {
122122449858SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
122222449858SCodrin Ciubotariu 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
122322449858SCodrin Ciubotariu 				vsc9953_port_learn_mode_set(i, mode[i]);
122422449858SCodrin Ciubotariu 		}
122522449858SCodrin Ciubotariu 	} else {
122622449858SCodrin Ciubotariu 		/* If administrative down, skip */
122722449858SCodrin Ciubotariu 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
122822449858SCodrin Ciubotariu 			vsc9953_port_learn_mode_set(port_no, mode[port_no]);
122922449858SCodrin Ciubotariu 	}
123022449858SCodrin Ciubotariu 
123122449858SCodrin Ciubotariu 	/* reset FDB port and VLAN FDB selection */
123222449858SCodrin Ciubotariu 	clrbits_le32(&l2ana_reg->ana.anag_efil, VSC9953_AGE_PORT_EN |
123322449858SCodrin Ciubotariu 		     VSC9953_AGE_PORT_MASK | VSC9953_AGE_VID_EN |
123422449858SCodrin Ciubotariu 		     VSC9953_AGE_VID_MASK);
123522449858SCodrin Ciubotariu }
123622449858SCodrin Ciubotariu 
123722449858SCodrin Ciubotariu /* Add a static FDB entry */
vsc9953_mac_table_add(u8 port_no,uchar mac[6],int vid)123822449858SCodrin Ciubotariu static int vsc9953_mac_table_add(u8 port_no, uchar mac[6], int vid)
123922449858SCodrin Ciubotariu {
124022449858SCodrin Ciubotariu 	u32 val;
124122449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
124222449858SCodrin Ciubotariu 
124322449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
124422449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
124522449858SCodrin Ciubotariu 
124622449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
124722449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
124822449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
124922449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
125022449858SCodrin Ciubotariu 
125122449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data,
125222449858SCodrin Ciubotariu 		 (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
125322449858SCodrin Ciubotariu 		 (mac[5] << 0));
125422449858SCodrin Ciubotariu 
125522449858SCodrin Ciubotariu 	/* set on which port is the MAC address added */
125622449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mac_access);
125722449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MAC_DESTIDX_MASK, port_no);
125822449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mac_access, val);
125922449858SCodrin Ciubotariu 
126022449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_LEARN) < 0)
126122449858SCodrin Ciubotariu 		return -1;
126222449858SCodrin Ciubotariu 
126322449858SCodrin Ciubotariu 	/* check if the MAC address was indeed added */
126422449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
126522449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
126622449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
126722449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
126822449858SCodrin Ciubotariu 
126922449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data,
127022449858SCodrin Ciubotariu 		 (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
127122449858SCodrin Ciubotariu 		 (mac[5] << 0));
127222449858SCodrin Ciubotariu 
127322449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_READ) < 0)
127422449858SCodrin Ciubotariu 		return -1;
127522449858SCodrin Ciubotariu 
127622449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mac_access);
127722449858SCodrin Ciubotariu 
127822449858SCodrin Ciubotariu 	if ((port_no != bitfield_extract_by_mask(val,
127922449858SCodrin Ciubotariu 						 VSC9953_MAC_DESTIDX_MASK))) {
128022449858SCodrin Ciubotariu 		printf("Failed to add MAC address\n");
128122449858SCodrin Ciubotariu 		return -1;
128222449858SCodrin Ciubotariu 	}
128322449858SCodrin Ciubotariu 	return 0;
128422449858SCodrin Ciubotariu }
128522449858SCodrin Ciubotariu 
128622449858SCodrin Ciubotariu /* Delete a FDB entry */
vsc9953_mac_table_del(uchar mac[6],u16 vid)128722449858SCodrin Ciubotariu static int vsc9953_mac_table_del(uchar mac[6], u16 vid)
128822449858SCodrin Ciubotariu {
128922449858SCodrin Ciubotariu 	u32 val;
129022449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
129122449858SCodrin Ciubotariu 
129222449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
129322449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
129422449858SCodrin Ciubotariu 
129522449858SCodrin Ciubotariu 	/* check first if MAC entry is present */
129622449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
129722449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
129822449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
129922449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
130022449858SCodrin Ciubotariu 
130122449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data,
130222449858SCodrin Ciubotariu 		 (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
130322449858SCodrin Ciubotariu 		 (mac[5] << 0));
130422449858SCodrin Ciubotariu 
130522449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_LOOKUP) < 0) {
130622449858SCodrin Ciubotariu 		debug("Lookup in the MAC table failed\n");
130722449858SCodrin Ciubotariu 		return -1;
130822449858SCodrin Ciubotariu 	}
130922449858SCodrin Ciubotariu 
131022449858SCodrin Ciubotariu 	if (!(in_le32(&l2ana_reg->ana_tables.mac_access) &
131122449858SCodrin Ciubotariu 	      VSC9953_MAC_CMD_VALID)) {
131222449858SCodrin Ciubotariu 		printf("The MAC address: %02x:%02x:%02x:%02x:%02x:%02x ",
131322449858SCodrin Ciubotariu 		       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
131422449858SCodrin Ciubotariu 		printf("VLAN: %d does not exist.\n", vid);
131522449858SCodrin Ciubotariu 		return -1;
131622449858SCodrin Ciubotariu 	}
131722449858SCodrin Ciubotariu 
131822449858SCodrin Ciubotariu 	/* FDB entry found, proceed to delete */
131922449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
132022449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
132122449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
132222449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
132322449858SCodrin Ciubotariu 
132422449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) |
132522449858SCodrin Ciubotariu 		 (mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0));
132622449858SCodrin Ciubotariu 
132722449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_FORGET) < 0)
132822449858SCodrin Ciubotariu 		return -1;
132922449858SCodrin Ciubotariu 
133022449858SCodrin Ciubotariu 	/* check if the MAC entry is still in FDB */
133122449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana_tables.mach_data);
133222449858SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) |
133322449858SCodrin Ciubotariu 	      (mac[0] << 8) | (mac[1] << 0);
133422449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.mach_data, val);
133522449858SCodrin Ciubotariu 
133622449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) |
133722449858SCodrin Ciubotariu 		 (mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0));
133822449858SCodrin Ciubotariu 
133922449858SCodrin Ciubotariu 	if (vsc9953_mac_table_cmd(MAC_TABLE_LOOKUP) < 0) {
134022449858SCodrin Ciubotariu 		debug("Lookup in the MAC table failed\n");
134122449858SCodrin Ciubotariu 		return -1;
134222449858SCodrin Ciubotariu 	}
134322449858SCodrin Ciubotariu 	if (in_le32(&l2ana_reg->ana_tables.mac_access) &
134422449858SCodrin Ciubotariu 	    VSC9953_MAC_CMD_VALID) {
134522449858SCodrin Ciubotariu 		printf("Failed to delete MAC address\n");
134622449858SCodrin Ciubotariu 		return -1;
134722449858SCodrin Ciubotariu 	}
134822449858SCodrin Ciubotariu 
134922449858SCodrin Ciubotariu 	return 0;
135022449858SCodrin Ciubotariu }
135122449858SCodrin Ciubotariu 
135222449858SCodrin Ciubotariu /* age the unlocked entries in FDB */
vsc9953_mac_table_age(int port_no,int vid)135322449858SCodrin Ciubotariu static void vsc9953_mac_table_age(int port_no, int vid)
135422449858SCodrin Ciubotariu {
135522449858SCodrin Ciubotariu 	int rc[VSC9953_MAX_PORTS];
135622449858SCodrin Ciubotariu 	enum port_learn_mode mode[VSC9953_MAX_PORTS];
135722449858SCodrin Ciubotariu 	u32 val;
135822449858SCodrin Ciubotariu 	int i;
135922449858SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
136022449858SCodrin Ciubotariu 
136122449858SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
136222449858SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
136322449858SCodrin Ciubotariu 
136422449858SCodrin Ciubotariu 	/* set port and VID for selective aging */
136522449858SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana.anag_efil);
136622449858SCodrin Ciubotariu 	if (port_no != ETHSW_CMD_PORT_ALL) {
136722449858SCodrin Ciubotariu 		/* disable auto learning */
136822449858SCodrin Ciubotariu 		rc[port_no] = vsc9953_port_learn_mode_get(port_no,
136922449858SCodrin Ciubotariu 							  &mode[port_no]);
137022449858SCodrin Ciubotariu 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
137122449858SCodrin Ciubotariu 			vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE);
137222449858SCodrin Ciubotariu 
137322449858SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_AGE_PORT_MASK,
137422449858SCodrin Ciubotariu 					       port_no) | VSC9953_AGE_PORT_EN;
137522449858SCodrin Ciubotariu 	} else {
137622449858SCodrin Ciubotariu 		/* disable auto learning on all ports */
137722449858SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
137822449858SCodrin Ciubotariu 			rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]);
137922449858SCodrin Ciubotariu 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
138022449858SCodrin Ciubotariu 				vsc9953_port_learn_mode_set(i, PORT_LEARN_NONE);
138122449858SCodrin Ciubotariu 		}
138222449858SCodrin Ciubotariu 	}
138322449858SCodrin Ciubotariu 
138422449858SCodrin Ciubotariu 	if (vid != ETHSW_CMD_VLAN_ALL) {
138522449858SCodrin Ciubotariu 		val = bitfield_replace_by_mask(val, VSC9953_AGE_VID_MASK, vid) |
138622449858SCodrin Ciubotariu 		      VSC9953_AGE_VID_EN;
138722449858SCodrin Ciubotariu 	}
138822449858SCodrin Ciubotariu 	out_le32(&l2ana_reg->ana.anag_efil, val);
138922449858SCodrin Ciubotariu 
139022449858SCodrin Ciubotariu 	/* age the dynamic FDB entries */
139122449858SCodrin Ciubotariu 	vsc9953_mac_table_cmd(MAC_TABLE_AGE);
139222449858SCodrin Ciubotariu 
139322449858SCodrin Ciubotariu 	/* clear previously set port and VID */
139422449858SCodrin Ciubotariu 	clrbits_le32(&l2ana_reg->ana.anag_efil, VSC9953_AGE_PORT_EN |
139522449858SCodrin Ciubotariu 		     VSC9953_AGE_PORT_MASK | VSC9953_AGE_VID_EN |
139622449858SCodrin Ciubotariu 		     VSC9953_AGE_VID_MASK);
139722449858SCodrin Ciubotariu 
139822449858SCodrin Ciubotariu 	if (port_no != ETHSW_CMD_PORT_ALL) {
139922449858SCodrin Ciubotariu 		if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
140022449858SCodrin Ciubotariu 			vsc9953_port_learn_mode_set(port_no, mode[port_no]);
140122449858SCodrin Ciubotariu 	} else {
140222449858SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
140322449858SCodrin Ciubotariu 			if (!rc[i] && mode[i] != PORT_LEARN_NONE)
140422449858SCodrin Ciubotariu 				vsc9953_port_learn_mode_set(i, mode[i]);
140522449858SCodrin Ciubotariu 		}
140622449858SCodrin Ciubotariu 	}
140722449858SCodrin Ciubotariu }
140822449858SCodrin Ciubotariu 
140922449858SCodrin Ciubotariu /* Delete all the dynamic FDB entries */
vsc9953_mac_table_flush(int port,int vid)141022449858SCodrin Ciubotariu static void vsc9953_mac_table_flush(int port, int vid)
141122449858SCodrin Ciubotariu {
141222449858SCodrin Ciubotariu 	vsc9953_mac_table_age(port, vid);
141322449858SCodrin Ciubotariu 	vsc9953_mac_table_age(port, vid);
141422449858SCodrin Ciubotariu }
141522449858SCodrin Ciubotariu 
1416a2477924SCodrin Ciubotariu enum egress_vlan_tag {
1417a2477924SCodrin Ciubotariu 	EGR_TAG_CLASS = 0,
1418a2477924SCodrin Ciubotariu 	EGR_TAG_PVID,
1419a2477924SCodrin Ciubotariu };
1420a2477924SCodrin Ciubotariu 
1421a2477924SCodrin Ciubotariu /* Set egress tag mode for a VSC9953 port */
vsc9953_port_vlan_egress_tag_set(int port_no,enum egress_vlan_tag mode)1422a2477924SCodrin Ciubotariu static void vsc9953_port_vlan_egress_tag_set(int port_no,
1423a2477924SCodrin Ciubotariu 					     enum egress_vlan_tag mode)
1424a2477924SCodrin Ciubotariu {
1425a2477924SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
1426a2477924SCodrin Ciubotariu 
1427a2477924SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
1428a2477924SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
1429a2477924SCodrin Ciubotariu 
1430a2477924SCodrin Ciubotariu 	switch (mode) {
1431a2477924SCodrin Ciubotariu 	case EGR_TAG_CLASS:
1432a2477924SCodrin Ciubotariu 		clrbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
1433a2477924SCodrin Ciubotariu 			     VSC9953_TAG_VID_PVID);
1434a2477924SCodrin Ciubotariu 		break;
1435a2477924SCodrin Ciubotariu 	case EGR_TAG_PVID:
1436a2477924SCodrin Ciubotariu 		setbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
1437a2477924SCodrin Ciubotariu 			     VSC9953_TAG_VID_PVID);
1438a2477924SCodrin Ciubotariu 		break;
1439a2477924SCodrin Ciubotariu 	default:
1440a2477924SCodrin Ciubotariu 		printf("Unknown egress VLAN tag mode for port %d\n", port_no);
1441a2477924SCodrin Ciubotariu 	}
1442a2477924SCodrin Ciubotariu }
1443a2477924SCodrin Ciubotariu 
1444a2477924SCodrin Ciubotariu /* Get egress tag mode for a VSC9953 port */
vsc9953_port_vlan_egress_tag_get(int port_no,enum egress_vlan_tag * mode)1445a2477924SCodrin Ciubotariu static void vsc9953_port_vlan_egress_tag_get(int port_no,
1446a2477924SCodrin Ciubotariu 					     enum egress_vlan_tag *mode)
1447a2477924SCodrin Ciubotariu {
1448a2477924SCodrin Ciubotariu 	u32 val;
1449a2477924SCodrin Ciubotariu 	struct vsc9953_rew_reg *l2rew_reg;
1450a2477924SCodrin Ciubotariu 
1451a2477924SCodrin Ciubotariu 	l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
1452a2477924SCodrin Ciubotariu 			VSC9953_REW_OFFSET);
1453a2477924SCodrin Ciubotariu 
1454a2477924SCodrin Ciubotariu 	val = in_le32(&l2rew_reg->port[port_no].port_tag_cfg);
1455a2477924SCodrin Ciubotariu 	if (val & VSC9953_TAG_VID_PVID)
1456a2477924SCodrin Ciubotariu 		*mode = EGR_TAG_PVID;
1457a2477924SCodrin Ciubotariu 	else
1458a2477924SCodrin Ciubotariu 		*mode = EGR_TAG_CLASS;
1459a2477924SCodrin Ciubotariu }
1460a2477924SCodrin Ciubotariu 
146121d214fcSCodrin Ciubotariu /* VSC9953 VLAN learning modes */
146221d214fcSCodrin Ciubotariu enum vlan_learning_mode {
146321d214fcSCodrin Ciubotariu 	SHARED_VLAN_LEARNING,
146421d214fcSCodrin Ciubotariu 	PRIVATE_VLAN_LEARNING,
146521d214fcSCodrin Ciubotariu };
146621d214fcSCodrin Ciubotariu 
146721d214fcSCodrin Ciubotariu /* Set VLAN learning mode for VSC9953 */
vsc9953_vlan_learning_set(enum vlan_learning_mode lrn_mode)146821d214fcSCodrin Ciubotariu static void vsc9953_vlan_learning_set(enum vlan_learning_mode lrn_mode)
146921d214fcSCodrin Ciubotariu {
147021d214fcSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
147121d214fcSCodrin Ciubotariu 
147221d214fcSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
147321d214fcSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
147421d214fcSCodrin Ciubotariu 
147521d214fcSCodrin Ciubotariu 	switch (lrn_mode) {
147621d214fcSCodrin Ciubotariu 	case SHARED_VLAN_LEARNING:
147721d214fcSCodrin Ciubotariu 		setbits_le32(&l2ana_reg->ana.agen_ctrl, VSC9953_FID_MASK_ALL);
147821d214fcSCodrin Ciubotariu 		break;
147921d214fcSCodrin Ciubotariu 	case PRIVATE_VLAN_LEARNING:
148021d214fcSCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->ana.agen_ctrl, VSC9953_FID_MASK_ALL);
148121d214fcSCodrin Ciubotariu 		break;
148221d214fcSCodrin Ciubotariu 	default:
148321d214fcSCodrin Ciubotariu 		printf("Unknown VLAN learn mode\n");
148421d214fcSCodrin Ciubotariu 	}
148521d214fcSCodrin Ciubotariu }
148621d214fcSCodrin Ciubotariu 
148721d214fcSCodrin Ciubotariu /* Get VLAN learning mode for VSC9953 */
vsc9953_vlan_learning_get(enum vlan_learning_mode * lrn_mode)148821d214fcSCodrin Ciubotariu static int vsc9953_vlan_learning_get(enum vlan_learning_mode *lrn_mode)
148921d214fcSCodrin Ciubotariu {
149021d214fcSCodrin Ciubotariu 	u32 val;
149121d214fcSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
149221d214fcSCodrin Ciubotariu 
149321d214fcSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
149421d214fcSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
149521d214fcSCodrin Ciubotariu 
149621d214fcSCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana.agen_ctrl);
149721d214fcSCodrin Ciubotariu 
149821d214fcSCodrin Ciubotariu 	if (!(val & VSC9953_FID_MASK_ALL)) {
149921d214fcSCodrin Ciubotariu 		*lrn_mode = PRIVATE_VLAN_LEARNING;
150021d214fcSCodrin Ciubotariu 	} else if ((val & VSC9953_FID_MASK_ALL) == VSC9953_FID_MASK_ALL) {
150121d214fcSCodrin Ciubotariu 		*lrn_mode = SHARED_VLAN_LEARNING;
150221d214fcSCodrin Ciubotariu 	} else {
150321d214fcSCodrin Ciubotariu 		printf("Unknown VLAN learning mode\n");
150421d214fcSCodrin Ciubotariu 		return -EINVAL;
150521d214fcSCodrin Ciubotariu 	}
150621d214fcSCodrin Ciubotariu 
150721d214fcSCodrin Ciubotariu 	return 0;
150821d214fcSCodrin Ciubotariu }
150921d214fcSCodrin Ciubotariu 
15105ed1bacdSCodrin Ciubotariu /* Enable/disable VLAN ingress filtering on a VSC9953 port */
vsc9953_port_ingress_filtering_set(int port_no,int enabled)15115ed1bacdSCodrin Ciubotariu static void vsc9953_port_ingress_filtering_set(int port_no, int enabled)
15125ed1bacdSCodrin Ciubotariu {
15135ed1bacdSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
15145ed1bacdSCodrin Ciubotariu 
15155ed1bacdSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
15165ed1bacdSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
15175ed1bacdSCodrin Ciubotariu 
15185ed1bacdSCodrin Ciubotariu 	if (enabled)
15195ed1bacdSCodrin Ciubotariu 		setbits_le32(&l2ana_reg->ana.vlan_mask, 1 << port_no);
15205ed1bacdSCodrin Ciubotariu 	else
15215ed1bacdSCodrin Ciubotariu 		clrbits_le32(&l2ana_reg->ana.vlan_mask, 1 << port_no);
15225ed1bacdSCodrin Ciubotariu }
15235ed1bacdSCodrin Ciubotariu 
15245ed1bacdSCodrin Ciubotariu /* Return VLAN ingress filtering on a VSC9953 port */
vsc9953_port_ingress_filtering_get(int port_no)15255ed1bacdSCodrin Ciubotariu static int vsc9953_port_ingress_filtering_get(int port_no)
15265ed1bacdSCodrin Ciubotariu {
15275ed1bacdSCodrin Ciubotariu 	u32 val;
15285ed1bacdSCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
15295ed1bacdSCodrin Ciubotariu 
15305ed1bacdSCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
15315ed1bacdSCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
15325ed1bacdSCodrin Ciubotariu 
15335ed1bacdSCodrin Ciubotariu 	val = in_le32(&l2ana_reg->ana.vlan_mask);
15345ed1bacdSCodrin Ciubotariu 	return !!(val & (1 << port_no));
15355ed1bacdSCodrin Ciubotariu }
15365ed1bacdSCodrin Ciubotariu 
1537aae0e689SCodrin Ciubotariu /* Get the aggregation group of a port */
vsc9953_port_aggr_grp_get(int port_no,int * aggr_grp)1538aae0e689SCodrin Ciubotariu static int vsc9953_port_aggr_grp_get(int port_no, int *aggr_grp)
1539aae0e689SCodrin Ciubotariu {
1540aae0e689SCodrin Ciubotariu 	u32 val;
1541aae0e689SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
1542aae0e689SCodrin Ciubotariu 
1543aae0e689SCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no))
1544aae0e689SCodrin Ciubotariu 		return -EINVAL;
1545aae0e689SCodrin Ciubotariu 
1546aae0e689SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1547aae0e689SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
1548aae0e689SCodrin Ciubotariu 
1549aae0e689SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_no].port_cfg);
1550aae0e689SCodrin Ciubotariu 	*aggr_grp = bitfield_extract_by_mask(val,
1551aae0e689SCodrin Ciubotariu 					     VSC9953_PORT_CFG_PORTID_MASK);
1552aae0e689SCodrin Ciubotariu 
1553aae0e689SCodrin Ciubotariu 	return 0;
1554aae0e689SCodrin Ciubotariu }
1555aae0e689SCodrin Ciubotariu 
vsc9953_aggr_grp_members_get(int aggr_grp,u8 aggr_membr[VSC9953_MAX_PORTS])1556aae0e689SCodrin Ciubotariu static void vsc9953_aggr_grp_members_get(int aggr_grp,
1557aae0e689SCodrin Ciubotariu 					 u8 aggr_membr[VSC9953_MAX_PORTS])
1558aae0e689SCodrin Ciubotariu {
1559aae0e689SCodrin Ciubotariu 	int port_no;
1560aae0e689SCodrin Ciubotariu 	int aggr_membr_grp;
1561aae0e689SCodrin Ciubotariu 
1562aae0e689SCodrin Ciubotariu 	for (port_no = 0; port_no < VSC9953_MAX_PORTS; port_no++) {
1563aae0e689SCodrin Ciubotariu 		aggr_membr[port_no] = 0;
1564aae0e689SCodrin Ciubotariu 
1565aae0e689SCodrin Ciubotariu 		if (vsc9953_port_aggr_grp_get(port_no, &aggr_membr_grp))
1566aae0e689SCodrin Ciubotariu 			continue;
1567aae0e689SCodrin Ciubotariu 
1568aae0e689SCodrin Ciubotariu 		if (aggr_grp == aggr_membr_grp)
1569aae0e689SCodrin Ciubotariu 			aggr_membr[port_no] = 1;
1570aae0e689SCodrin Ciubotariu 	}
1571aae0e689SCodrin Ciubotariu }
1572aae0e689SCodrin Ciubotariu 
vsc9953_update_dest_members_masks(int port_no,u32 membr_bitfld_old,u32 membr_bitfld_new)1573aae0e689SCodrin Ciubotariu static void vsc9953_update_dest_members_masks(int port_no, u32 membr_bitfld_old,
1574aae0e689SCodrin Ciubotariu 					      u32 membr_bitfld_new)
1575aae0e689SCodrin Ciubotariu {
1576aae0e689SCodrin Ciubotariu 	int i;
1577aae0e689SCodrin Ciubotariu 	u32 pgid;
1578aae0e689SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
1579aae0e689SCodrin Ciubotariu 
1580aae0e689SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1581aae0e689SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
1582aae0e689SCodrin Ciubotariu 
1583aae0e689SCodrin Ciubotariu 	/*
1584aae0e689SCodrin Ciubotariu 	 * NOTE: Only the unicast destination masks are updated, since
1585aae0e689SCodrin Ciubotariu 	 * we do not support for now Layer-2 multicast entries
1586aae0e689SCodrin Ciubotariu 	 */
1587aae0e689SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++) {
1588aae0e689SCodrin Ciubotariu 		if (i == port_no) {
1589aae0e689SCodrin Ciubotariu 			clrsetbits_le32(&l2ana_reg->port_id_tbl.port_grp_id[i],
1590aae0e689SCodrin Ciubotariu 					VSC9953_PGID_PORT_MASK,
1591aae0e689SCodrin Ciubotariu 					membr_bitfld_new);
1592aae0e689SCodrin Ciubotariu 			continue;
1593aae0e689SCodrin Ciubotariu 		}
1594aae0e689SCodrin Ciubotariu 
1595aae0e689SCodrin Ciubotariu 		pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
1596aae0e689SCodrin Ciubotariu 		if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
1597aae0e689SCodrin Ciubotariu 			pgid &= ~((u32)(1 << port_no));
1598aae0e689SCodrin Ciubotariu 		if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
1599aae0e689SCodrin Ciubotariu 			pgid |= ((u32)(1 << port_no));
1600aae0e689SCodrin Ciubotariu 
1601aae0e689SCodrin Ciubotariu 		out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
1602aae0e689SCodrin Ciubotariu 	}
1603aae0e689SCodrin Ciubotariu }
1604aae0e689SCodrin Ciubotariu 
vsc9953_update_source_members_masks(int port_no,u32 membr_bitfld_old,u32 membr_bitfld_new)1605aae0e689SCodrin Ciubotariu static void vsc9953_update_source_members_masks(int port_no,
1606aae0e689SCodrin Ciubotariu 						u32 membr_bitfld_old,
1607aae0e689SCodrin Ciubotariu 						u32 membr_bitfld_new)
1608aae0e689SCodrin Ciubotariu {
1609aae0e689SCodrin Ciubotariu 	int i;
1610aae0e689SCodrin Ciubotariu 	int index;
1611aae0e689SCodrin Ciubotariu 	u32 pgid;
1612aae0e689SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
1613aae0e689SCodrin Ciubotariu 
1614aae0e689SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1615aae0e689SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
1616aae0e689SCodrin Ciubotariu 
1617aae0e689SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS + 1; i++) {
1618aae0e689SCodrin Ciubotariu 		index = PGID_SRC_START + i;
1619aae0e689SCodrin Ciubotariu 		pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[index]);
1620aae0e689SCodrin Ciubotariu 		if (i == port_no) {
1621aae0e689SCodrin Ciubotariu 			pgid = (pgid | VSC9953_PGID_PORT_MASK) &
1622aae0e689SCodrin Ciubotariu 			       ~membr_bitfld_new;
1623aae0e689SCodrin Ciubotariu 			out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index],
1624aae0e689SCodrin Ciubotariu 				 pgid);
1625aae0e689SCodrin Ciubotariu 			continue;
1626aae0e689SCodrin Ciubotariu 		}
1627aae0e689SCodrin Ciubotariu 
1628aae0e689SCodrin Ciubotariu 		if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
1629aae0e689SCodrin Ciubotariu 			pgid |= (u32)(1 << port_no);
1630aae0e689SCodrin Ciubotariu 
1631aae0e689SCodrin Ciubotariu 		if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
1632aae0e689SCodrin Ciubotariu 			pgid &= ~(u32)(1 << port_no);
1633aae0e689SCodrin Ciubotariu 		out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index], pgid);
1634aae0e689SCodrin Ciubotariu 	}
1635aae0e689SCodrin Ciubotariu }
1636aae0e689SCodrin Ciubotariu 
vsc9953_aggr_mask_get_next(u32 aggr_mask,u32 member_bitfield)1637aae0e689SCodrin Ciubotariu static u32 vsc9953_aggr_mask_get_next(u32 aggr_mask, u32 member_bitfield)
1638aae0e689SCodrin Ciubotariu {
1639aae0e689SCodrin Ciubotariu 	if (!member_bitfield)
1640aae0e689SCodrin Ciubotariu 		return 0;
1641aae0e689SCodrin Ciubotariu 
1642aae0e689SCodrin Ciubotariu 	if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
1643aae0e689SCodrin Ciubotariu 		aggr_mask = 1;
1644aae0e689SCodrin Ciubotariu 	else
1645aae0e689SCodrin Ciubotariu 		aggr_mask <<= 1;
1646aae0e689SCodrin Ciubotariu 
1647aae0e689SCodrin Ciubotariu 	while (!(aggr_mask & member_bitfield)) {
1648aae0e689SCodrin Ciubotariu 		aggr_mask <<= 1;
1649aae0e689SCodrin Ciubotariu 		if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
1650aae0e689SCodrin Ciubotariu 			aggr_mask = 1;
1651aae0e689SCodrin Ciubotariu 	}
1652aae0e689SCodrin Ciubotariu 
1653aae0e689SCodrin Ciubotariu 	return aggr_mask;
1654aae0e689SCodrin Ciubotariu }
1655aae0e689SCodrin Ciubotariu 
vsc9953_update_aggr_members_masks(int port_no,u32 membr_bitfld_old,u32 membr_bitfld_new)1656aae0e689SCodrin Ciubotariu static void vsc9953_update_aggr_members_masks(int port_no, u32 membr_bitfld_old,
1657aae0e689SCodrin Ciubotariu 					      u32 membr_bitfld_new)
1658aae0e689SCodrin Ciubotariu {
1659aae0e689SCodrin Ciubotariu 	int i;
1660aae0e689SCodrin Ciubotariu 	u32 pgid;
1661aae0e689SCodrin Ciubotariu 	u32 aggr_mask_old = 0;
1662aae0e689SCodrin Ciubotariu 	u32 aggr_mask_new = 0;
1663aae0e689SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
1664aae0e689SCodrin Ciubotariu 
1665aae0e689SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1666aae0e689SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
1667aae0e689SCodrin Ciubotariu 
1668aae0e689SCodrin Ciubotariu 	/* Update all the PGID aggregation masks */
1669aae0e689SCodrin Ciubotariu 	for (i = PGID_AGGR_START; i < PGID_SRC_START; i++) {
1670aae0e689SCodrin Ciubotariu 		pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
1671aae0e689SCodrin Ciubotariu 
1672aae0e689SCodrin Ciubotariu 		aggr_mask_old = vsc9953_aggr_mask_get_next(aggr_mask_old,
1673aae0e689SCodrin Ciubotariu 							   membr_bitfld_old);
1674aae0e689SCodrin Ciubotariu 		pgid = (pgid & ~membr_bitfld_old) | aggr_mask_old;
1675aae0e689SCodrin Ciubotariu 
1676aae0e689SCodrin Ciubotariu 		aggr_mask_new = vsc9953_aggr_mask_get_next(aggr_mask_new,
1677aae0e689SCodrin Ciubotariu 							   membr_bitfld_new);
1678aae0e689SCodrin Ciubotariu 		pgid = (pgid & ~membr_bitfld_new) | aggr_mask_new;
1679aae0e689SCodrin Ciubotariu 
1680aae0e689SCodrin Ciubotariu 		out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
1681aae0e689SCodrin Ciubotariu 	}
1682aae0e689SCodrin Ciubotariu }
1683aae0e689SCodrin Ciubotariu 
vsc9953_aggr_membr_bitfield_get(u8 member[VSC9953_MAX_PORTS])1684aae0e689SCodrin Ciubotariu static u32 vsc9953_aggr_membr_bitfield_get(u8 member[VSC9953_MAX_PORTS])
1685aae0e689SCodrin Ciubotariu {
1686aae0e689SCodrin Ciubotariu 	int i;
1687aae0e689SCodrin Ciubotariu 	u32 member_bitfield = 0;
1688aae0e689SCodrin Ciubotariu 
1689aae0e689SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++) {
1690aae0e689SCodrin Ciubotariu 		if (member[i])
1691aae0e689SCodrin Ciubotariu 			member_bitfield |= 1 << i;
1692aae0e689SCodrin Ciubotariu 	}
1693aae0e689SCodrin Ciubotariu 	member_bitfield &= VSC9953_PGID_PORT_MASK;
1694aae0e689SCodrin Ciubotariu 
1695aae0e689SCodrin Ciubotariu 	return member_bitfield;
1696aae0e689SCodrin Ciubotariu }
1697aae0e689SCodrin Ciubotariu 
vsc9953_update_members_masks(int port_no,u8 member_old[VSC9953_MAX_PORTS],u8 member_new[VSC9953_MAX_PORTS])1698aae0e689SCodrin Ciubotariu static void vsc9953_update_members_masks(int port_no,
1699aae0e689SCodrin Ciubotariu 					 u8 member_old[VSC9953_MAX_PORTS],
1700aae0e689SCodrin Ciubotariu 					 u8 member_new[VSC9953_MAX_PORTS])
1701aae0e689SCodrin Ciubotariu {
1702aae0e689SCodrin Ciubotariu 	u32 membr_bitfld_old = vsc9953_aggr_membr_bitfield_get(member_old);
1703aae0e689SCodrin Ciubotariu 	u32 membr_bitfld_new = vsc9953_aggr_membr_bitfield_get(member_new);
1704aae0e689SCodrin Ciubotariu 
1705aae0e689SCodrin Ciubotariu 	vsc9953_update_dest_members_masks(port_no, membr_bitfld_old,
1706aae0e689SCodrin Ciubotariu 					  membr_bitfld_new);
1707aae0e689SCodrin Ciubotariu 	vsc9953_update_source_members_masks(port_no, membr_bitfld_old,
1708aae0e689SCodrin Ciubotariu 					    membr_bitfld_new);
1709aae0e689SCodrin Ciubotariu 	vsc9953_update_aggr_members_masks(port_no, membr_bitfld_old,
1710aae0e689SCodrin Ciubotariu 					  membr_bitfld_new);
1711aae0e689SCodrin Ciubotariu }
1712aae0e689SCodrin Ciubotariu 
1713aae0e689SCodrin Ciubotariu /* Set the aggregation group of a port */
vsc9953_port_aggr_grp_set(int port_no,int aggr_grp)1714aae0e689SCodrin Ciubotariu static int vsc9953_port_aggr_grp_set(int port_no, int aggr_grp)
1715aae0e689SCodrin Ciubotariu {
1716aae0e689SCodrin Ciubotariu 	u8 aggr_membr_old[VSC9953_MAX_PORTS];
1717aae0e689SCodrin Ciubotariu 	u8 aggr_membr_new[VSC9953_MAX_PORTS];
1718aae0e689SCodrin Ciubotariu 	int rc;
1719aae0e689SCodrin Ciubotariu 	int aggr_grp_old;
1720aae0e689SCodrin Ciubotariu 	u32 val;
1721aae0e689SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
1722aae0e689SCodrin Ciubotariu 
1723aae0e689SCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(port_no) || !VSC9953_PORT_CHECK(aggr_grp))
1724aae0e689SCodrin Ciubotariu 		return -EINVAL;
1725aae0e689SCodrin Ciubotariu 
1726aae0e689SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
1727aae0e689SCodrin Ciubotariu 						VSC9953_ANA_OFFSET);
1728aae0e689SCodrin Ciubotariu 
1729aae0e689SCodrin Ciubotariu 	rc = vsc9953_port_aggr_grp_get(port_no, &aggr_grp_old);
1730aae0e689SCodrin Ciubotariu 	if (rc)
1731aae0e689SCodrin Ciubotariu 		return rc;
1732aae0e689SCodrin Ciubotariu 
1733aae0e689SCodrin Ciubotariu 	/* get all the members of the old aggregation group */
1734aae0e689SCodrin Ciubotariu 	vsc9953_aggr_grp_members_get(aggr_grp_old, aggr_membr_old);
1735aae0e689SCodrin Ciubotariu 
1736aae0e689SCodrin Ciubotariu 	/* get all the members of the same aggregation group */
1737aae0e689SCodrin Ciubotariu 	vsc9953_aggr_grp_members_get(aggr_grp, aggr_membr_new);
1738aae0e689SCodrin Ciubotariu 
1739aae0e689SCodrin Ciubotariu 	/* add current port as member to the new aggregation group */
1740aae0e689SCodrin Ciubotariu 	aggr_membr_old[port_no] = 0;
1741aae0e689SCodrin Ciubotariu 	aggr_membr_new[port_no] = 1;
1742aae0e689SCodrin Ciubotariu 
1743aae0e689SCodrin Ciubotariu 	/* update masks */
1744aae0e689SCodrin Ciubotariu 	vsc9953_update_members_masks(port_no, aggr_membr_old, aggr_membr_new);
1745aae0e689SCodrin Ciubotariu 
1746aae0e689SCodrin Ciubotariu 	/* Change logical port number */
1747aae0e689SCodrin Ciubotariu 	val = in_le32(&l2ana_reg->port[port_no].port_cfg);
1748aae0e689SCodrin Ciubotariu 	val = bitfield_replace_by_mask(val,
1749aae0e689SCodrin Ciubotariu 				       VSC9953_PORT_CFG_PORTID_MASK, aggr_grp);
1750aae0e689SCodrin Ciubotariu 	out_le32(&l2ana_reg->port[port_no].port_cfg, val);
1751aae0e689SCodrin Ciubotariu 
1752aae0e689SCodrin Ciubotariu 	return 0;
1753aae0e689SCodrin Ciubotariu }
1754aae0e689SCodrin Ciubotariu 
vsc9953_port_status_key_func(struct ethsw_command_def * parsed_cmd)175524a23debSCodrin Ciubotariu static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd)
175624a23debSCodrin Ciubotariu {
175724a23debSCodrin Ciubotariu 	int i;
175824a23debSCodrin Ciubotariu 	u8 enabled;
175924a23debSCodrin Ciubotariu 
176024a23debSCodrin Ciubotariu 	/* Last keyword should tell us if we should enable/disable the port */
176124a23debSCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
176224a23debSCodrin Ciubotariu 	    ethsw_id_enable)
176324a23debSCodrin Ciubotariu 		enabled = 1;
176424a23debSCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
176524a23debSCodrin Ciubotariu 		 ethsw_id_disable)
176624a23debSCodrin Ciubotariu 		enabled = 0;
176724a23debSCodrin Ciubotariu 	else
176824a23debSCodrin Ciubotariu 		return CMD_RET_USAGE;
176924a23debSCodrin Ciubotariu 
177024a23debSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
177124a23debSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
177224a23debSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
177324a23debSCodrin Ciubotariu 			return CMD_RET_FAILURE;
177424a23debSCodrin Ciubotariu 		}
177524a23debSCodrin Ciubotariu 		vsc9953_port_status_set(parsed_cmd->port, enabled);
177624a23debSCodrin Ciubotariu 	} else {
177724a23debSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
177824a23debSCodrin Ciubotariu 			vsc9953_port_status_set(i, enabled);
177924a23debSCodrin Ciubotariu 	}
178024a23debSCodrin Ciubotariu 
178124a23debSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
178224a23debSCodrin Ciubotariu }
178324a23debSCodrin Ciubotariu 
vsc9953_port_config_key_func(struct ethsw_command_def * parsed_cmd)178424a23debSCodrin Ciubotariu static int vsc9953_port_config_key_func(struct ethsw_command_def *parsed_cmd)
178524a23debSCodrin Ciubotariu {
178624a23debSCodrin Ciubotariu 	int i;
178724a23debSCodrin Ciubotariu 
178824a23debSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
178924a23debSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
179024a23debSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
179124a23debSCodrin Ciubotariu 			return CMD_RET_FAILURE;
179224a23debSCodrin Ciubotariu 		}
179324a23debSCodrin Ciubotariu 		vsc9953_phy_autoneg(parsed_cmd->port);
179424a23debSCodrin Ciubotariu 		printf("%8s %8s %8s %8s %8s\n",
179524a23debSCodrin Ciubotariu 		       "Port", "Status", "Link", "Speed",
179624a23debSCodrin Ciubotariu 		       "Duplex");
179724a23debSCodrin Ciubotariu 		vsc9953_port_config_show(parsed_cmd->port);
179824a23debSCodrin Ciubotariu 
179924a23debSCodrin Ciubotariu 	} else {
180024a23debSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
180124a23debSCodrin Ciubotariu 			vsc9953_phy_autoneg(i);
180224a23debSCodrin Ciubotariu 		printf("%8s %8s %8s %8s %8s\n",
180324a23debSCodrin Ciubotariu 		       "Port", "Status", "Link", "Speed", "Duplex");
180424a23debSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
180524a23debSCodrin Ciubotariu 			vsc9953_port_config_show(i);
180624a23debSCodrin Ciubotariu 	}
180724a23debSCodrin Ciubotariu 
180824a23debSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
180924a23debSCodrin Ciubotariu }
181024a23debSCodrin Ciubotariu 
vsc9953_port_stats_key_func(struct ethsw_command_def * parsed_cmd)181186719f0cSCodrin Ciubotariu static int vsc9953_port_stats_key_func(struct ethsw_command_def *parsed_cmd)
181286719f0cSCodrin Ciubotariu {
181386719f0cSCodrin Ciubotariu 	int i;
181486719f0cSCodrin Ciubotariu 
181586719f0cSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
181686719f0cSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
181786719f0cSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
181886719f0cSCodrin Ciubotariu 			return CMD_RET_FAILURE;
181986719f0cSCodrin Ciubotariu 		}
182086719f0cSCodrin Ciubotariu 		vsc9953_port_statistics_show(parsed_cmd->port);
182186719f0cSCodrin Ciubotariu 	} else {
182286719f0cSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
182386719f0cSCodrin Ciubotariu 			vsc9953_port_statistics_show(i);
182486719f0cSCodrin Ciubotariu 	}
182586719f0cSCodrin Ciubotariu 
182686719f0cSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
182786719f0cSCodrin Ciubotariu }
182886719f0cSCodrin Ciubotariu 
vsc9953_port_stats_clear_key_func(struct ethsw_command_def * parsed_cmd)182986719f0cSCodrin Ciubotariu static int vsc9953_port_stats_clear_key_func(struct ethsw_command_def
183086719f0cSCodrin Ciubotariu 					     *parsed_cmd)
183186719f0cSCodrin Ciubotariu {
183286719f0cSCodrin Ciubotariu 	int i;
183386719f0cSCodrin Ciubotariu 
183486719f0cSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
183586719f0cSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
183686719f0cSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
183786719f0cSCodrin Ciubotariu 			return CMD_RET_FAILURE;
183886719f0cSCodrin Ciubotariu 		}
183986719f0cSCodrin Ciubotariu 		vsc9953_port_statistics_clear(parsed_cmd->port);
184086719f0cSCodrin Ciubotariu 	} else {
184186719f0cSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
184286719f0cSCodrin Ciubotariu 			vsc9953_port_statistics_clear(i);
184386719f0cSCodrin Ciubotariu 	}
184486719f0cSCodrin Ciubotariu 
184586719f0cSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
184686719f0cSCodrin Ciubotariu }
184786719f0cSCodrin Ciubotariu 
vsc9953_learn_show_key_func(struct ethsw_command_def * parsed_cmd)184868c929daSCodrin Ciubotariu static int vsc9953_learn_show_key_func(struct ethsw_command_def *parsed_cmd)
184968c929daSCodrin Ciubotariu {
185068c929daSCodrin Ciubotariu 	int i;
185168c929daSCodrin Ciubotariu 	enum port_learn_mode mode;
185268c929daSCodrin Ciubotariu 
185368c929daSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
185468c929daSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
185568c929daSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
185668c929daSCodrin Ciubotariu 			return CMD_RET_FAILURE;
185768c929daSCodrin Ciubotariu 		}
185868c929daSCodrin Ciubotariu 		if (vsc9953_port_learn_mode_get(parsed_cmd->port, &mode))
185968c929daSCodrin Ciubotariu 			return CMD_RET_FAILURE;
186068c929daSCodrin Ciubotariu 		printf("%7s %11s\n", "Port", "Learn mode");
186168c929daSCodrin Ciubotariu 		switch (mode) {
186268c929daSCodrin Ciubotariu 		case PORT_LEARN_NONE:
186368c929daSCodrin Ciubotariu 			printf("%7d %11s\n", parsed_cmd->port, "disable");
186468c929daSCodrin Ciubotariu 			break;
186568c929daSCodrin Ciubotariu 		case PORT_LEARN_AUTO:
186668c929daSCodrin Ciubotariu 			printf("%7d %11s\n", parsed_cmd->port, "auto");
186768c929daSCodrin Ciubotariu 			break;
186868c929daSCodrin Ciubotariu 		default:
186968c929daSCodrin Ciubotariu 			printf("%7d %11s\n", parsed_cmd->port, "-");
187068c929daSCodrin Ciubotariu 		}
187168c929daSCodrin Ciubotariu 	} else {
187268c929daSCodrin Ciubotariu 		printf("%7s %11s\n", "Port", "Learn mode");
187368c929daSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
187468c929daSCodrin Ciubotariu 			if (vsc9953_port_learn_mode_get(i, &mode))
187568c929daSCodrin Ciubotariu 				continue;
187668c929daSCodrin Ciubotariu 			switch (mode) {
187768c929daSCodrin Ciubotariu 			case PORT_LEARN_NONE:
187868c929daSCodrin Ciubotariu 				printf("%7d %11s\n", i, "disable");
187968c929daSCodrin Ciubotariu 				break;
188068c929daSCodrin Ciubotariu 			case PORT_LEARN_AUTO:
188168c929daSCodrin Ciubotariu 				printf("%7d %11s\n", i, "auto");
188268c929daSCodrin Ciubotariu 				break;
188368c929daSCodrin Ciubotariu 			default:
188468c929daSCodrin Ciubotariu 				printf("%7d %11s\n", i, "-");
188568c929daSCodrin Ciubotariu 			}
188668c929daSCodrin Ciubotariu 		}
188768c929daSCodrin Ciubotariu 	}
188868c929daSCodrin Ciubotariu 
188968c929daSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
189068c929daSCodrin Ciubotariu }
189168c929daSCodrin Ciubotariu 
vsc9953_learn_set_key_func(struct ethsw_command_def * parsed_cmd)189268c929daSCodrin Ciubotariu static int vsc9953_learn_set_key_func(struct ethsw_command_def *parsed_cmd)
189368c929daSCodrin Ciubotariu {
189468c929daSCodrin Ciubotariu 	int i;
189568c929daSCodrin Ciubotariu 	enum port_learn_mode mode;
189668c929daSCodrin Ciubotariu 
189768c929daSCodrin Ciubotariu 	/* Last keyword should tell us the learn mode */
189868c929daSCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
189968c929daSCodrin Ciubotariu 	    ethsw_id_auto)
190068c929daSCodrin Ciubotariu 		mode = PORT_LEARN_AUTO;
190168c929daSCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
190268c929daSCodrin Ciubotariu 		 ethsw_id_disable)
190368c929daSCodrin Ciubotariu 		mode = PORT_LEARN_NONE;
190468c929daSCodrin Ciubotariu 	else
190568c929daSCodrin Ciubotariu 		return CMD_RET_USAGE;
190668c929daSCodrin Ciubotariu 
190768c929daSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
190868c929daSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
190968c929daSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
191068c929daSCodrin Ciubotariu 			return CMD_RET_FAILURE;
191168c929daSCodrin Ciubotariu 		}
191268c929daSCodrin Ciubotariu 		vsc9953_port_learn_mode_set(parsed_cmd->port, mode);
191368c929daSCodrin Ciubotariu 	} else {
191468c929daSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
191568c929daSCodrin Ciubotariu 			vsc9953_port_learn_mode_set(i, mode);
191668c929daSCodrin Ciubotariu 	}
191768c929daSCodrin Ciubotariu 
191868c929daSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
191968c929daSCodrin Ciubotariu }
192068c929daSCodrin Ciubotariu 
vsc9953_fdb_show_key_func(struct ethsw_command_def * parsed_cmd)192122449858SCodrin Ciubotariu static int vsc9953_fdb_show_key_func(struct ethsw_command_def *parsed_cmd)
192222449858SCodrin Ciubotariu {
192322449858SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL &&
192422449858SCodrin Ciubotariu 	    !VSC9953_PORT_CHECK(parsed_cmd->port)) {
192522449858SCodrin Ciubotariu 		printf("Invalid port number: %d\n", parsed_cmd->port);
192622449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
192722449858SCodrin Ciubotariu 	}
192822449858SCodrin Ciubotariu 
192922449858SCodrin Ciubotariu 	if (parsed_cmd->vid != ETHSW_CMD_VLAN_ALL &&
193022449858SCodrin Ciubotariu 	    !VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
193122449858SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
193222449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
193322449858SCodrin Ciubotariu 	}
193422449858SCodrin Ciubotariu 
193522449858SCodrin Ciubotariu 	vsc9953_mac_table_show(parsed_cmd->port, parsed_cmd->vid);
193622449858SCodrin Ciubotariu 
193722449858SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
193822449858SCodrin Ciubotariu }
193922449858SCodrin Ciubotariu 
vsc9953_fdb_flush_key_func(struct ethsw_command_def * parsed_cmd)194022449858SCodrin Ciubotariu static int vsc9953_fdb_flush_key_func(struct ethsw_command_def *parsed_cmd)
194122449858SCodrin Ciubotariu {
194222449858SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL &&
194322449858SCodrin Ciubotariu 	    !VSC9953_PORT_CHECK(parsed_cmd->port)) {
194422449858SCodrin Ciubotariu 		printf("Invalid port number: %d\n", parsed_cmd->port);
194522449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
194622449858SCodrin Ciubotariu 	}
194722449858SCodrin Ciubotariu 
194822449858SCodrin Ciubotariu 	if (parsed_cmd->vid != ETHSW_CMD_VLAN_ALL &&
194922449858SCodrin Ciubotariu 	    !VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
195022449858SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
195122449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
195222449858SCodrin Ciubotariu 	}
195322449858SCodrin Ciubotariu 
195422449858SCodrin Ciubotariu 	vsc9953_mac_table_flush(parsed_cmd->port, parsed_cmd->vid);
195522449858SCodrin Ciubotariu 
195622449858SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
195722449858SCodrin Ciubotariu }
195822449858SCodrin Ciubotariu 
vsc9953_fdb_entry_add_key_func(struct ethsw_command_def * parsed_cmd)195922449858SCodrin Ciubotariu static int vsc9953_fdb_entry_add_key_func(struct ethsw_command_def *parsed_cmd)
196022449858SCodrin Ciubotariu {
196122449858SCodrin Ciubotariu 	int vid;
196222449858SCodrin Ciubotariu 
196322449858SCodrin Ciubotariu 	/* a port number must be present */
196422449858SCodrin Ciubotariu 	if (parsed_cmd->port == ETHSW_CMD_PORT_ALL) {
196522449858SCodrin Ciubotariu 		printf("Please specify a port\n");
196622449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
196722449858SCodrin Ciubotariu 	}
196822449858SCodrin Ciubotariu 
196922449858SCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
197022449858SCodrin Ciubotariu 		printf("Invalid port number: %d\n", parsed_cmd->port);
197122449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
197222449858SCodrin Ciubotariu 	}
197322449858SCodrin Ciubotariu 
197422449858SCodrin Ciubotariu 	/* Use VLAN 1 if VID is not set */
197522449858SCodrin Ciubotariu 	vid = (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL ? 1 : parsed_cmd->vid);
197622449858SCodrin Ciubotariu 
197722449858SCodrin Ciubotariu 	if (!VSC9953_VLAN_CHECK(vid)) {
197822449858SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", vid);
197922449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
198022449858SCodrin Ciubotariu 	}
198122449858SCodrin Ciubotariu 
198222449858SCodrin Ciubotariu 	if (vsc9953_mac_table_add(parsed_cmd->port, parsed_cmd->ethaddr, vid))
198322449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
198422449858SCodrin Ciubotariu 
198522449858SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
198622449858SCodrin Ciubotariu }
198722449858SCodrin Ciubotariu 
vsc9953_fdb_entry_del_key_func(struct ethsw_command_def * parsed_cmd)198822449858SCodrin Ciubotariu static int vsc9953_fdb_entry_del_key_func(struct ethsw_command_def *parsed_cmd)
198922449858SCodrin Ciubotariu {
199022449858SCodrin Ciubotariu 	int vid;
199122449858SCodrin Ciubotariu 
199222449858SCodrin Ciubotariu 	/* Use VLAN 1 if VID is not set */
199322449858SCodrin Ciubotariu 	vid = (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL ? 1 : parsed_cmd->vid);
199422449858SCodrin Ciubotariu 
199522449858SCodrin Ciubotariu 	if (!VSC9953_VLAN_CHECK(vid)) {
199622449858SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", vid);
199722449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
199822449858SCodrin Ciubotariu 	}
199922449858SCodrin Ciubotariu 
200022449858SCodrin Ciubotariu 	if (vsc9953_mac_table_del(parsed_cmd->ethaddr, vid))
200122449858SCodrin Ciubotariu 		return CMD_RET_FAILURE;
200222449858SCodrin Ciubotariu 
200322449858SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
200422449858SCodrin Ciubotariu }
200522449858SCodrin Ciubotariu 
vsc9953_pvid_show_key_func(struct ethsw_command_def * parsed_cmd)2006a2477924SCodrin Ciubotariu static int vsc9953_pvid_show_key_func(struct ethsw_command_def *parsed_cmd)
2007a2477924SCodrin Ciubotariu {
2008a2477924SCodrin Ciubotariu 	int i;
2009a2477924SCodrin Ciubotariu 	int pvid;
2010a2477924SCodrin Ciubotariu 
2011a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2012a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2013a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2014a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2015a2477924SCodrin Ciubotariu 		}
2016a2477924SCodrin Ciubotariu 
2017a2477924SCodrin Ciubotariu 		if (vsc9953_port_vlan_pvid_get(parsed_cmd->port, &pvid))
2018a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2019a2477924SCodrin Ciubotariu 		printf("%7s %7s\n", "Port", "PVID");
2020a2477924SCodrin Ciubotariu 		printf("%7d %7d\n", parsed_cmd->port, pvid);
2021a2477924SCodrin Ciubotariu 	} else {
2022a2477924SCodrin Ciubotariu 		printf("%7s %7s\n", "Port", "PVID");
2023a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
2024a2477924SCodrin Ciubotariu 			if (vsc9953_port_vlan_pvid_get(i, &pvid))
2025a2477924SCodrin Ciubotariu 				continue;
2026a2477924SCodrin Ciubotariu 			printf("%7d %7d\n", i, pvid);
2027a2477924SCodrin Ciubotariu 		}
2028a2477924SCodrin Ciubotariu 	}
2029a2477924SCodrin Ciubotariu 
2030a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2031a2477924SCodrin Ciubotariu }
2032a2477924SCodrin Ciubotariu 
vsc9953_pvid_set_key_func(struct ethsw_command_def * parsed_cmd)2033a2477924SCodrin Ciubotariu static int vsc9953_pvid_set_key_func(struct ethsw_command_def *parsed_cmd)
2034a2477924SCodrin Ciubotariu {
2035a2477924SCodrin Ciubotariu 	/* PVID number should be set in parsed_cmd->vid */
2036a2477924SCodrin Ciubotariu 	if (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL) {
2037a2477924SCodrin Ciubotariu 		printf("Please set a pvid value\n");
2038a2477924SCodrin Ciubotariu 		return CMD_RET_FAILURE;
2039a2477924SCodrin Ciubotariu 	}
2040a2477924SCodrin Ciubotariu 
2041a2477924SCodrin Ciubotariu 	if (!VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
2042a2477924SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
2043a2477924SCodrin Ciubotariu 		return CMD_RET_FAILURE;
2044a2477924SCodrin Ciubotariu 	}
2045a2477924SCodrin Ciubotariu 
2046a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2047a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2048a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2049a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2050a2477924SCodrin Ciubotariu 		}
2051a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_pvid_set(parsed_cmd->port, parsed_cmd->vid);
2052a2477924SCodrin Ciubotariu 	} else {
2053a2477924SCodrin Ciubotariu 		vsc9953_port_all_vlan_pvid_set(parsed_cmd->vid);
2054a2477924SCodrin Ciubotariu 	}
2055a2477924SCodrin Ciubotariu 
2056a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2057a2477924SCodrin Ciubotariu }
2058a2477924SCodrin Ciubotariu 
vsc9953_vlan_show_key_func(struct ethsw_command_def * parsed_cmd)2059a2477924SCodrin Ciubotariu static int vsc9953_vlan_show_key_func(struct ethsw_command_def *parsed_cmd)
2060a2477924SCodrin Ciubotariu {
2061a2477924SCodrin Ciubotariu 	int i;
2062a2477924SCodrin Ciubotariu 
2063a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2064a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2065a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2066a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2067a2477924SCodrin Ciubotariu 		}
2068a2477924SCodrin Ciubotariu 		vsc9953_vlan_membership_show(parsed_cmd->port);
2069a2477924SCodrin Ciubotariu 	} else {
2070a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2071a2477924SCodrin Ciubotariu 			vsc9953_vlan_membership_show(i);
2072a2477924SCodrin Ciubotariu 	}
2073a2477924SCodrin Ciubotariu 
2074a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2075a2477924SCodrin Ciubotariu }
2076a2477924SCodrin Ciubotariu 
vsc9953_vlan_set_key_func(struct ethsw_command_def * parsed_cmd)2077a2477924SCodrin Ciubotariu static int vsc9953_vlan_set_key_func(struct ethsw_command_def *parsed_cmd)
2078a2477924SCodrin Ciubotariu {
2079a2477924SCodrin Ciubotariu 	int i;
2080a2477924SCodrin Ciubotariu 	int add;
2081a2477924SCodrin Ciubotariu 
2082a2477924SCodrin Ciubotariu 	/* VLAN should be set in parsed_cmd->vid */
2083a2477924SCodrin Ciubotariu 	if (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL) {
2084a2477924SCodrin Ciubotariu 		printf("Please set a vlan value\n");
2085a2477924SCodrin Ciubotariu 		return CMD_RET_FAILURE;
2086a2477924SCodrin Ciubotariu 	}
2087a2477924SCodrin Ciubotariu 
2088a2477924SCodrin Ciubotariu 	if (!VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
2089a2477924SCodrin Ciubotariu 		printf("Invalid VID number: %d\n", parsed_cmd->vid);
2090a2477924SCodrin Ciubotariu 		return CMD_RET_FAILURE;
2091a2477924SCodrin Ciubotariu 	}
2092a2477924SCodrin Ciubotariu 
2093a2477924SCodrin Ciubotariu 	/* keywords add/delete should be the last but one in array */
2094a2477924SCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] ==
2095a2477924SCodrin Ciubotariu 	    ethsw_id_add)
2096a2477924SCodrin Ciubotariu 		add = 1;
2097a2477924SCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] ==
2098a2477924SCodrin Ciubotariu 		 ethsw_id_del)
2099a2477924SCodrin Ciubotariu 		add = 0;
2100a2477924SCodrin Ciubotariu 	else
2101a2477924SCodrin Ciubotariu 		return CMD_RET_USAGE;
2102a2477924SCodrin Ciubotariu 
2103a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2104a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2105a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2106a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2107a2477924SCodrin Ciubotariu 		}
2108a2477924SCodrin Ciubotariu 		vsc9953_vlan_table_membership_set(parsed_cmd->vid,
2109a2477924SCodrin Ciubotariu 						  parsed_cmd->port, add);
2110a2477924SCodrin Ciubotariu 	} else {
2111a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2112a2477924SCodrin Ciubotariu 			vsc9953_vlan_table_membership_set(parsed_cmd->vid, i,
2113a2477924SCodrin Ciubotariu 							  add);
2114a2477924SCodrin Ciubotariu 	}
2115a2477924SCodrin Ciubotariu 
2116a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2117a2477924SCodrin Ciubotariu }
vsc9953_port_untag_show_key_func(struct ethsw_command_def * parsed_cmd)2118a2477924SCodrin Ciubotariu static int vsc9953_port_untag_show_key_func(
2119a2477924SCodrin Ciubotariu 		struct ethsw_command_def *parsed_cmd)
2120a2477924SCodrin Ciubotariu {
2121a2477924SCodrin Ciubotariu 	int i;
2122a2477924SCodrin Ciubotariu 
2123a2477924SCodrin Ciubotariu 	printf("%7s\t%17s\n", "Port", "Untag");
2124a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2125a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2126a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2127a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2128a2477924SCodrin Ciubotariu 		}
2129a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_egr_untag_show(parsed_cmd->port);
2130a2477924SCodrin Ciubotariu 	} else {
2131a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2132a2477924SCodrin Ciubotariu 			vsc9953_port_vlan_egr_untag_show(i);
2133a2477924SCodrin Ciubotariu 	}
2134a2477924SCodrin Ciubotariu 
2135a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2136a2477924SCodrin Ciubotariu }
2137a2477924SCodrin Ciubotariu 
vsc9953_port_untag_set_key_func(struct ethsw_command_def * parsed_cmd)2138a2477924SCodrin Ciubotariu static int vsc9953_port_untag_set_key_func(struct ethsw_command_def *parsed_cmd)
2139a2477924SCodrin Ciubotariu {
2140a2477924SCodrin Ciubotariu 	int i;
2141a2477924SCodrin Ciubotariu 	enum egress_untag_mode mode;
2142a2477924SCodrin Ciubotariu 
2143a2477924SCodrin Ciubotariu 	/* keywords for the untagged mode are the last in the array */
2144a2477924SCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2145a2477924SCodrin Ciubotariu 	    ethsw_id_all)
2146a2477924SCodrin Ciubotariu 		mode = EGRESS_UNTAG_ALL;
2147a2477924SCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2148a2477924SCodrin Ciubotariu 		 ethsw_id_none)
2149a2477924SCodrin Ciubotariu 		mode = EGRESS_UNTAG_NONE;
2150a2477924SCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2151a2477924SCodrin Ciubotariu 		 ethsw_id_pvid)
2152a2477924SCodrin Ciubotariu 		mode = EGRESS_UNTAG_PVID_AND_ZERO;
2153a2477924SCodrin Ciubotariu 	else
2154a2477924SCodrin Ciubotariu 		return CMD_RET_USAGE;
2155a2477924SCodrin Ciubotariu 
2156a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2157a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2158a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2159a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2160a2477924SCodrin Ciubotariu 		}
2161a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_egr_untag_set(parsed_cmd->port, mode);
2162a2477924SCodrin Ciubotariu 	} else {
2163a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2164a2477924SCodrin Ciubotariu 			vsc9953_port_vlan_egr_untag_set(i, mode);
2165a2477924SCodrin Ciubotariu 	}
2166a2477924SCodrin Ciubotariu 
2167a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2168a2477924SCodrin Ciubotariu }
2169a2477924SCodrin Ciubotariu 
vsc9953_egr_vlan_tag_show_key_func(struct ethsw_command_def * parsed_cmd)2170a2477924SCodrin Ciubotariu static int vsc9953_egr_vlan_tag_show_key_func(
2171a2477924SCodrin Ciubotariu 		struct ethsw_command_def *parsed_cmd)
2172a2477924SCodrin Ciubotariu {
2173a2477924SCodrin Ciubotariu 	int i;
2174a2477924SCodrin Ciubotariu 	enum egress_vlan_tag mode;
2175a2477924SCodrin Ciubotariu 
2176a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2177a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2178a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2179a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2180a2477924SCodrin Ciubotariu 		}
2181a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_egress_tag_get(parsed_cmd->port, &mode);
2182a2477924SCodrin Ciubotariu 		printf("%7s\t%12s\n", "Port", "Egress VID");
2183a2477924SCodrin Ciubotariu 		printf("%7d\t", parsed_cmd->port);
2184a2477924SCodrin Ciubotariu 		switch (mode) {
2185a2477924SCodrin Ciubotariu 		case EGR_TAG_CLASS:
2186a2477924SCodrin Ciubotariu 			printf("%12s\n", "classified");
2187a2477924SCodrin Ciubotariu 			break;
2188a2477924SCodrin Ciubotariu 		case EGR_TAG_PVID:
2189a2477924SCodrin Ciubotariu 			printf("%12s\n", "pvid");
2190a2477924SCodrin Ciubotariu 			break;
2191a2477924SCodrin Ciubotariu 		default:
2192a2477924SCodrin Ciubotariu 			printf("%12s\n", "-");
2193a2477924SCodrin Ciubotariu 		}
2194a2477924SCodrin Ciubotariu 	} else {
2195a2477924SCodrin Ciubotariu 		printf("%7s\t%12s\n", "Port", "Egress VID");
2196a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
2197a2477924SCodrin Ciubotariu 			vsc9953_port_vlan_egress_tag_get(i, &mode);
2198a2477924SCodrin Ciubotariu 			switch (mode) {
2199a2477924SCodrin Ciubotariu 			case EGR_TAG_CLASS:
2200a2477924SCodrin Ciubotariu 				printf("%7d\t%12s\n", i, "classified");
2201a2477924SCodrin Ciubotariu 				break;
2202a2477924SCodrin Ciubotariu 			case EGR_TAG_PVID:
2203a2477924SCodrin Ciubotariu 				printf("%7d\t%12s\n", i, "pvid");
2204a2477924SCodrin Ciubotariu 				break;
2205a2477924SCodrin Ciubotariu 			default:
2206a2477924SCodrin Ciubotariu 				printf("%7d\t%12s\n", i, "-");
2207a2477924SCodrin Ciubotariu 			}
2208a2477924SCodrin Ciubotariu 		}
2209a2477924SCodrin Ciubotariu 	}
2210a2477924SCodrin Ciubotariu 
2211a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2212a2477924SCodrin Ciubotariu }
2213a2477924SCodrin Ciubotariu 
vsc9953_egr_vlan_tag_set_key_func(struct ethsw_command_def * parsed_cmd)2214a2477924SCodrin Ciubotariu static int vsc9953_egr_vlan_tag_set_key_func(
2215a2477924SCodrin Ciubotariu 		struct ethsw_command_def *parsed_cmd)
2216a2477924SCodrin Ciubotariu {
2217a2477924SCodrin Ciubotariu 	int i;
2218a2477924SCodrin Ciubotariu 	enum egress_vlan_tag mode;
2219a2477924SCodrin Ciubotariu 
2220a2477924SCodrin Ciubotariu 	/* keywords for the egress vlan tag mode are the last in the array */
2221a2477924SCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2222a2477924SCodrin Ciubotariu 	    ethsw_id_pvid)
2223a2477924SCodrin Ciubotariu 		mode = EGR_TAG_PVID;
2224a2477924SCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
2225a2477924SCodrin Ciubotariu 		 ethsw_id_classified)
2226a2477924SCodrin Ciubotariu 		mode = EGR_TAG_CLASS;
2227a2477924SCodrin Ciubotariu 	else
2228a2477924SCodrin Ciubotariu 		return CMD_RET_USAGE;
2229a2477924SCodrin Ciubotariu 
2230a2477924SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2231a2477924SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2232a2477924SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2233a2477924SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2234a2477924SCodrin Ciubotariu 		}
2235a2477924SCodrin Ciubotariu 		vsc9953_port_vlan_egress_tag_set(parsed_cmd->port, mode);
2236a2477924SCodrin Ciubotariu 	} else {
2237a2477924SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
2238a2477924SCodrin Ciubotariu 			vsc9953_port_vlan_egress_tag_set(i, mode);
2239a2477924SCodrin Ciubotariu 	}
2240a2477924SCodrin Ciubotariu 
2241a2477924SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2242a2477924SCodrin Ciubotariu }
2243a2477924SCodrin Ciubotariu 
vsc9953_vlan_learn_show_key_func(struct ethsw_command_def * parsed_cmd)224421d214fcSCodrin Ciubotariu static int vsc9953_vlan_learn_show_key_func(
224521d214fcSCodrin Ciubotariu 		struct ethsw_command_def *parsed_cmd)
224621d214fcSCodrin Ciubotariu {
224721d214fcSCodrin Ciubotariu 	int rc;
224821d214fcSCodrin Ciubotariu 	enum vlan_learning_mode mode;
224921d214fcSCodrin Ciubotariu 
225021d214fcSCodrin Ciubotariu 	rc = vsc9953_vlan_learning_get(&mode);
225121d214fcSCodrin Ciubotariu 	if (rc)
225221d214fcSCodrin Ciubotariu 		return CMD_RET_FAILURE;
225321d214fcSCodrin Ciubotariu 
225421d214fcSCodrin Ciubotariu 	switch (mode) {
225521d214fcSCodrin Ciubotariu 	case SHARED_VLAN_LEARNING:
225621d214fcSCodrin Ciubotariu 		printf("VLAN learning mode: shared\n");
225721d214fcSCodrin Ciubotariu 		break;
225821d214fcSCodrin Ciubotariu 	case PRIVATE_VLAN_LEARNING:
225921d214fcSCodrin Ciubotariu 		printf("VLAN learning mode: private\n");
226021d214fcSCodrin Ciubotariu 		break;
226121d214fcSCodrin Ciubotariu 	default:
226221d214fcSCodrin Ciubotariu 		printf("Unknown VLAN learning mode\n");
226321d214fcSCodrin Ciubotariu 		rc = CMD_RET_FAILURE;
226421d214fcSCodrin Ciubotariu 	}
226521d214fcSCodrin Ciubotariu 
226621d214fcSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
226721d214fcSCodrin Ciubotariu }
226821d214fcSCodrin Ciubotariu 
vsc9953_vlan_learn_set_key_func(struct ethsw_command_def * parsed_cmd)226921d214fcSCodrin Ciubotariu static int vsc9953_vlan_learn_set_key_func(struct ethsw_command_def *parsed_cmd)
227021d214fcSCodrin Ciubotariu {
227121d214fcSCodrin Ciubotariu 	enum vlan_learning_mode mode;
227221d214fcSCodrin Ciubotariu 
227321d214fcSCodrin Ciubotariu 	/* keywords for shared/private are the last in the array */
227421d214fcSCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
227521d214fcSCodrin Ciubotariu 	    ethsw_id_shared)
227621d214fcSCodrin Ciubotariu 		mode = SHARED_VLAN_LEARNING;
227721d214fcSCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
227821d214fcSCodrin Ciubotariu 		 ethsw_id_private)
227921d214fcSCodrin Ciubotariu 		mode = PRIVATE_VLAN_LEARNING;
228021d214fcSCodrin Ciubotariu 	else
228121d214fcSCodrin Ciubotariu 		return CMD_RET_USAGE;
228221d214fcSCodrin Ciubotariu 
228321d214fcSCodrin Ciubotariu 	vsc9953_vlan_learning_set(mode);
228421d214fcSCodrin Ciubotariu 
228521d214fcSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
228621d214fcSCodrin Ciubotariu }
228721d214fcSCodrin Ciubotariu 
vsc9953_ingr_fltr_show_key_func(struct ethsw_command_def * parsed_cmd)22885ed1bacdSCodrin Ciubotariu static int vsc9953_ingr_fltr_show_key_func(struct ethsw_command_def *parsed_cmd)
22895ed1bacdSCodrin Ciubotariu {
22905ed1bacdSCodrin Ciubotariu 	int i;
22915ed1bacdSCodrin Ciubotariu 	int enabled;
22925ed1bacdSCodrin Ciubotariu 
22935ed1bacdSCodrin Ciubotariu 	printf("%7s\t%18s\n", "Port", "Ingress filtering");
22945ed1bacdSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
22955ed1bacdSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
22965ed1bacdSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
22975ed1bacdSCodrin Ciubotariu 			return CMD_RET_FAILURE;
22985ed1bacdSCodrin Ciubotariu 		}
22995ed1bacdSCodrin Ciubotariu 		enabled = vsc9953_port_ingress_filtering_get(parsed_cmd->port);
23005ed1bacdSCodrin Ciubotariu 		printf("%7d\t%18s\n", parsed_cmd->port, enabled ? "enable" :
23015ed1bacdSCodrin Ciubotariu 								  "disable");
23025ed1bacdSCodrin Ciubotariu 	} else {
23035ed1bacdSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
23045ed1bacdSCodrin Ciubotariu 			enabled = vsc9953_port_ingress_filtering_get(i);
23055ed1bacdSCodrin Ciubotariu 			printf("%7d\t%18s\n", parsed_cmd->port, enabled ?
23065ed1bacdSCodrin Ciubotariu 								"enable" :
23075ed1bacdSCodrin Ciubotariu 								"disable");
23085ed1bacdSCodrin Ciubotariu 		}
23095ed1bacdSCodrin Ciubotariu 	}
23105ed1bacdSCodrin Ciubotariu 
23115ed1bacdSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
23125ed1bacdSCodrin Ciubotariu }
23135ed1bacdSCodrin Ciubotariu 
vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def * parsed_cmd)23145ed1bacdSCodrin Ciubotariu static int vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def *parsed_cmd)
23155ed1bacdSCodrin Ciubotariu {
23165ed1bacdSCodrin Ciubotariu 	int i;
23175ed1bacdSCodrin Ciubotariu 	int enable;
23185ed1bacdSCodrin Ciubotariu 
23195ed1bacdSCodrin Ciubotariu 	/* keywords for enabling/disabling ingress filtering
23205ed1bacdSCodrin Ciubotariu 	 * are the last in the array
23215ed1bacdSCodrin Ciubotariu 	 */
23225ed1bacdSCodrin Ciubotariu 	if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
23235ed1bacdSCodrin Ciubotariu 	    ethsw_id_enable)
23245ed1bacdSCodrin Ciubotariu 		enable = 1;
23255ed1bacdSCodrin Ciubotariu 	else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
23265ed1bacdSCodrin Ciubotariu 		 ethsw_id_disable)
23275ed1bacdSCodrin Ciubotariu 		enable = 0;
23285ed1bacdSCodrin Ciubotariu 	else
23295ed1bacdSCodrin Ciubotariu 		return CMD_RET_USAGE;
23305ed1bacdSCodrin Ciubotariu 
23315ed1bacdSCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
23325ed1bacdSCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
23335ed1bacdSCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
23345ed1bacdSCodrin Ciubotariu 			return CMD_RET_FAILURE;
23355ed1bacdSCodrin Ciubotariu 		}
23365ed1bacdSCodrin Ciubotariu 		vsc9953_port_ingress_filtering_set(parsed_cmd->port, enable);
23375ed1bacdSCodrin Ciubotariu 	} else {
23385ed1bacdSCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++)
23395ed1bacdSCodrin Ciubotariu 			vsc9953_port_ingress_filtering_set(i, enable);
23405ed1bacdSCodrin Ciubotariu 	}
23415ed1bacdSCodrin Ciubotariu 
23425ed1bacdSCodrin Ciubotariu 	return CMD_RET_SUCCESS;
23435ed1bacdSCodrin Ciubotariu }
23445ed1bacdSCodrin Ciubotariu 
vsc9953_port_aggr_show_key_func(struct ethsw_command_def * parsed_cmd)2345aae0e689SCodrin Ciubotariu static int vsc9953_port_aggr_show_key_func(struct ethsw_command_def *parsed_cmd)
2346aae0e689SCodrin Ciubotariu {
2347aae0e689SCodrin Ciubotariu 	int i;
2348aae0e689SCodrin Ciubotariu 	int aggr_grp;
2349aae0e689SCodrin Ciubotariu 
2350aae0e689SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2351aae0e689SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2352aae0e689SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2353aae0e689SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2354aae0e689SCodrin Ciubotariu 		}
2355aae0e689SCodrin Ciubotariu 
2356aae0e689SCodrin Ciubotariu 		if (vsc9953_port_aggr_grp_get(parsed_cmd->port, &aggr_grp))
2357aae0e689SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2358aae0e689SCodrin Ciubotariu 		printf("%7s %10s\n", "Port", "Aggr grp");
2359aae0e689SCodrin Ciubotariu 		printf("%7d %10d\n", parsed_cmd->port, aggr_grp);
2360aae0e689SCodrin Ciubotariu 	} else {
2361aae0e689SCodrin Ciubotariu 		printf("%7s %10s\n", "Port", "Aggr grp");
2362aae0e689SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
2363aae0e689SCodrin Ciubotariu 			if (vsc9953_port_aggr_grp_get(i, &aggr_grp))
2364aae0e689SCodrin Ciubotariu 				continue;
2365aae0e689SCodrin Ciubotariu 			printf("%7d %10d\n", i, aggr_grp);
2366aae0e689SCodrin Ciubotariu 		}
2367aae0e689SCodrin Ciubotariu 	}
2368aae0e689SCodrin Ciubotariu 
2369aae0e689SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2370aae0e689SCodrin Ciubotariu }
2371aae0e689SCodrin Ciubotariu 
vsc9953_port_aggr_set_key_func(struct ethsw_command_def * parsed_cmd)2372aae0e689SCodrin Ciubotariu static int vsc9953_port_aggr_set_key_func(struct ethsw_command_def *parsed_cmd)
2373aae0e689SCodrin Ciubotariu {
2374aae0e689SCodrin Ciubotariu 	int i;
2375aae0e689SCodrin Ciubotariu 
2376aae0e689SCodrin Ciubotariu 	/* Aggregation group number should be set in parsed_cmd->aggr_grp */
2377aae0e689SCodrin Ciubotariu 	if (parsed_cmd->aggr_grp == ETHSW_CMD_AGGR_GRP_NONE) {
2378aae0e689SCodrin Ciubotariu 		printf("Please set an aggregation group value\n");
2379aae0e689SCodrin Ciubotariu 		return CMD_RET_FAILURE;
2380aae0e689SCodrin Ciubotariu 	}
2381aae0e689SCodrin Ciubotariu 
2382aae0e689SCodrin Ciubotariu 	if (!VSC9953_PORT_CHECK(parsed_cmd->aggr_grp)) {
2383aae0e689SCodrin Ciubotariu 		printf("Invalid aggregation group number: %d\n",
2384aae0e689SCodrin Ciubotariu 		       parsed_cmd->aggr_grp);
2385aae0e689SCodrin Ciubotariu 		return CMD_RET_FAILURE;
2386aae0e689SCodrin Ciubotariu 	}
2387aae0e689SCodrin Ciubotariu 
2388aae0e689SCodrin Ciubotariu 	if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
2389aae0e689SCodrin Ciubotariu 		if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
2390aae0e689SCodrin Ciubotariu 			printf("Invalid port number: %d\n", parsed_cmd->port);
2391aae0e689SCodrin Ciubotariu 			return CMD_RET_FAILURE;
2392aae0e689SCodrin Ciubotariu 		}
2393aae0e689SCodrin Ciubotariu 		if (vsc9953_port_aggr_grp_set(parsed_cmd->port,
2394aae0e689SCodrin Ciubotariu 					      parsed_cmd->aggr_grp)) {
2395aae0e689SCodrin Ciubotariu 			printf("Port %d: failed to set aggr group %d\n",
2396aae0e689SCodrin Ciubotariu 			       parsed_cmd->port, parsed_cmd->aggr_grp);
2397aae0e689SCodrin Ciubotariu 		}
2398aae0e689SCodrin Ciubotariu 	} else {
2399aae0e689SCodrin Ciubotariu 		for (i = 0; i < VSC9953_MAX_PORTS; i++) {
2400aae0e689SCodrin Ciubotariu 			if (vsc9953_port_aggr_grp_set(i,
2401aae0e689SCodrin Ciubotariu 						      parsed_cmd->aggr_grp)) {
2402aae0e689SCodrin Ciubotariu 				printf("Port %d: failed to set aggr group %d\n",
2403aae0e689SCodrin Ciubotariu 				       i, parsed_cmd->aggr_grp);
2404aae0e689SCodrin Ciubotariu 			}
2405aae0e689SCodrin Ciubotariu 		}
2406aae0e689SCodrin Ciubotariu 	}
2407aae0e689SCodrin Ciubotariu 
2408aae0e689SCodrin Ciubotariu 	return CMD_RET_SUCCESS;
2409aae0e689SCodrin Ciubotariu }
2410aae0e689SCodrin Ciubotariu 
241124a23debSCodrin Ciubotariu static struct ethsw_command_func vsc9953_cmd_func = {
241224a23debSCodrin Ciubotariu 		.ethsw_name = "L2 Switch VSC9953",
241324a23debSCodrin Ciubotariu 		.port_enable = &vsc9953_port_status_key_func,
241424a23debSCodrin Ciubotariu 		.port_disable = &vsc9953_port_status_key_func,
241524a23debSCodrin Ciubotariu 		.port_show = &vsc9953_port_config_key_func,
241686719f0cSCodrin Ciubotariu 		.port_stats = &vsc9953_port_stats_key_func,
241786719f0cSCodrin Ciubotariu 		.port_stats_clear = &vsc9953_port_stats_clear_key_func,
241868c929daSCodrin Ciubotariu 		.port_learn = &vsc9953_learn_set_key_func,
241968c929daSCodrin Ciubotariu 		.port_learn_show = &vsc9953_learn_show_key_func,
242022449858SCodrin Ciubotariu 		.fdb_show = &vsc9953_fdb_show_key_func,
242122449858SCodrin Ciubotariu 		.fdb_flush = &vsc9953_fdb_flush_key_func,
242222449858SCodrin Ciubotariu 		.fdb_entry_add = &vsc9953_fdb_entry_add_key_func,
242322449858SCodrin Ciubotariu 		.fdb_entry_del = &vsc9953_fdb_entry_del_key_func,
2424a2477924SCodrin Ciubotariu 		.pvid_show = &vsc9953_pvid_show_key_func,
2425a2477924SCodrin Ciubotariu 		.pvid_set = &vsc9953_pvid_set_key_func,
2426a2477924SCodrin Ciubotariu 		.vlan_show = &vsc9953_vlan_show_key_func,
2427a2477924SCodrin Ciubotariu 		.vlan_set = &vsc9953_vlan_set_key_func,
2428a2477924SCodrin Ciubotariu 		.port_untag_show = &vsc9953_port_untag_show_key_func,
2429a2477924SCodrin Ciubotariu 		.port_untag_set = &vsc9953_port_untag_set_key_func,
2430a2477924SCodrin Ciubotariu 		.port_egr_vlan_show = &vsc9953_egr_vlan_tag_show_key_func,
2431a2477924SCodrin Ciubotariu 		.port_egr_vlan_set = &vsc9953_egr_vlan_tag_set_key_func,
243221d214fcSCodrin Ciubotariu 		.vlan_learn_show = &vsc9953_vlan_learn_show_key_func,
243321d214fcSCodrin Ciubotariu 		.vlan_learn_set = &vsc9953_vlan_learn_set_key_func,
24345ed1bacdSCodrin Ciubotariu 		.port_ingr_filt_show = &vsc9953_ingr_fltr_show_key_func,
2435aae0e689SCodrin Ciubotariu 		.port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func,
2436aae0e689SCodrin Ciubotariu 		.port_aggr_show = &vsc9953_port_aggr_show_key_func,
2437aae0e689SCodrin Ciubotariu 		.port_aggr_set = &vsc9953_port_aggr_set_key_func,
243824a23debSCodrin Ciubotariu };
243924a23debSCodrin Ciubotariu 
244024a23debSCodrin Ciubotariu #endif /* CONFIG_CMD_ETHSW */
244124a23debSCodrin Ciubotariu 
24429de05987SCodrin Ciubotariu /*****************************************************************************
24439de05987SCodrin Ciubotariu At startup, the default configuration would be:
24449de05987SCodrin Ciubotariu 	- HW learning enabled on all ports; (HW default)
24459de05987SCodrin Ciubotariu 	- All ports are in VLAN 1;
24469de05987SCodrin Ciubotariu 	- All ports are VLAN aware;
24479de05987SCodrin Ciubotariu 	- All ports have POP_COUNT 1;
24489de05987SCodrin Ciubotariu 	- All ports have PVID 1;
24499de05987SCodrin Ciubotariu 	- All ports have TPID 0x8100; (HW default)
24509de05987SCodrin Ciubotariu 	- All ports tag frames classified to all VLANs that are not PVID;
24519de05987SCodrin Ciubotariu *****************************************************************************/
vsc9953_default_configuration(void)24529de05987SCodrin Ciubotariu void vsc9953_default_configuration(void)
24539de05987SCodrin Ciubotariu {
24549de05987SCodrin Ciubotariu 	int i;
24559de05987SCodrin Ciubotariu 
2456ba389e65SCodrin Ciubotariu 	if (vsc9953_autoage_time_set(VSC9953_DEFAULT_AGE_TIME))
2457ba389e65SCodrin Ciubotariu 		debug("VSC9953: failed to set AGE time to %d\n",
2458ba389e65SCodrin Ciubotariu 		      VSC9953_DEFAULT_AGE_TIME);
2459ba389e65SCodrin Ciubotariu 
24609de05987SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_VLAN; i++)
24619de05987SCodrin Ciubotariu 		vsc9953_vlan_table_membership_all_set(i, 0);
24629de05987SCodrin Ciubotariu 	vsc9953_port_all_vlan_aware_set(1);
24639de05987SCodrin Ciubotariu 	vsc9953_port_all_vlan_pvid_set(1);
24649de05987SCodrin Ciubotariu 	vsc9953_port_all_vlan_poncnt_set(1);
24659de05987SCodrin Ciubotariu 	vsc9953_vlan_table_membership_all_set(1, 1);
24669de05987SCodrin Ciubotariu 	vsc9953_vlan_ingr_fltr_learn_drop(1);
24679de05987SCodrin Ciubotariu 	vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO);
2468aae0e689SCodrin Ciubotariu 	if (vsc9953_aggr_code_set(AGGR_CODE_ALL))
2469aae0e689SCodrin Ciubotariu 		debug("VSC9953: failed to set default aggregation code mode\n");
24709de05987SCodrin Ciubotariu }
24719de05987SCodrin Ciubotariu 
vsc9953_init(bd_t * bis)24726706b115SCodrin Ciubotariu void vsc9953_init(bd_t *bis)
24736706b115SCodrin Ciubotariu {
24743cc8cfffSCodrin Ciubotariu 	u32 i;
24753cc8cfffSCodrin Ciubotariu 	u32 hdx_cfg = 0;
24763cc8cfffSCodrin Ciubotariu 	u32 phy_addr = 0;
24776706b115SCodrin Ciubotariu 	int timeout;
24786706b115SCodrin Ciubotariu 	struct vsc9953_system_reg *l2sys_reg;
24796706b115SCodrin Ciubotariu 	struct vsc9953_qsys_reg *l2qsys_reg;
24806706b115SCodrin Ciubotariu 	struct vsc9953_dev_gmii *l2dev_gmii_reg;
24816706b115SCodrin Ciubotariu 	struct vsc9953_analyzer *l2ana_reg;
24826706b115SCodrin Ciubotariu 	struct vsc9953_devcpu_gcb *l2dev_gcb;
24836706b115SCodrin Ciubotariu 
24846706b115SCodrin Ciubotariu 	l2dev_gmii_reg = (struct vsc9953_dev_gmii *)(VSC9953_OFFSET +
24856706b115SCodrin Ciubotariu 			VSC9953_DEV_GMII_OFFSET);
24866706b115SCodrin Ciubotariu 
24876706b115SCodrin Ciubotariu 	l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
24886706b115SCodrin Ciubotariu 			VSC9953_ANA_OFFSET);
24896706b115SCodrin Ciubotariu 
24906706b115SCodrin Ciubotariu 	l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET +
24916706b115SCodrin Ciubotariu 			VSC9953_SYS_OFFSET);
24926706b115SCodrin Ciubotariu 
24936706b115SCodrin Ciubotariu 	l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
24946706b115SCodrin Ciubotariu 			VSC9953_QSYS_OFFSET);
24956706b115SCodrin Ciubotariu 
24966706b115SCodrin Ciubotariu 	l2dev_gcb = (struct vsc9953_devcpu_gcb *)(VSC9953_OFFSET +
24976706b115SCodrin Ciubotariu 			VSC9953_DEVCPU_GCB);
24986706b115SCodrin Ciubotariu 
24996706b115SCodrin Ciubotariu 	out_le32(&l2dev_gcb->chip_regs.soft_rst,
2500c4390486SCodrin Ciubotariu 		 VSC9953_SOFT_SWC_RST_ENA);
25016706b115SCodrin Ciubotariu 	timeout = 50000;
25026706b115SCodrin Ciubotariu 	while ((in_le32(&l2dev_gcb->chip_regs.soft_rst) &
2503c4390486SCodrin Ciubotariu 			VSC9953_SOFT_SWC_RST_ENA) && --timeout)
25046706b115SCodrin Ciubotariu 		udelay(1); /* busy wait for vsc9953 soft reset */
25056706b115SCodrin Ciubotariu 	if (timeout == 0)
25066706b115SCodrin Ciubotariu 		debug("Timeout waiting for VSC9953 to reset\n");
25076706b115SCodrin Ciubotariu 
2508c4390486SCodrin Ciubotariu 	out_le32(&l2sys_reg->sys.reset_cfg, VSC9953_MEM_ENABLE |
2509c4390486SCodrin Ciubotariu 		 VSC9953_MEM_INIT);
25106706b115SCodrin Ciubotariu 
25116706b115SCodrin Ciubotariu 	timeout = 50000;
25126706b115SCodrin Ciubotariu 	while ((in_le32(&l2sys_reg->sys.reset_cfg) &
2513c4390486SCodrin Ciubotariu 		VSC9953_MEM_INIT) && --timeout)
25146706b115SCodrin Ciubotariu 		udelay(1); /* busy wait for vsc9953 memory init */
25156706b115SCodrin Ciubotariu 	if (timeout == 0)
25166706b115SCodrin Ciubotariu 		debug("Timeout waiting for VSC9953 memory to initialize\n");
25176706b115SCodrin Ciubotariu 
25186706b115SCodrin Ciubotariu 	out_le32(&l2sys_reg->sys.reset_cfg, (in_le32(&l2sys_reg->sys.reset_cfg)
2519c4390486SCodrin Ciubotariu 			| VSC9953_CORE_ENABLE));
25206706b115SCodrin Ciubotariu 
25216706b115SCodrin Ciubotariu 	/* VSC9953 Setting to be done once only */
25226706b115SCodrin Ciubotariu 	out_le32(&l2qsys_reg->sys.ext_cpu_cfg, 0x00000b00);
25236706b115SCodrin Ciubotariu 
25246706b115SCodrin Ciubotariu 	for (i = 0; i < VSC9953_MAX_PORTS; i++) {
25256706b115SCodrin Ciubotariu 		if (vsc9953_port_init(i))
25266706b115SCodrin Ciubotariu 			printf("Failed to initialize l2switch port %d\n", i);
25276706b115SCodrin Ciubotariu 
252802c00f26SCodrin Ciubotariu 		if (!vsc9953_l2sw.port[i].enabled)
252902c00f26SCodrin Ciubotariu 			continue;
253002c00f26SCodrin Ciubotariu 
25316706b115SCodrin Ciubotariu 		/* Enable VSC9953 GMII Ports Port ID 0 - 7 */
25326706b115SCodrin Ciubotariu 		if (VSC9953_INTERNAL_PORT_CHECK(i)) {
25336706b115SCodrin Ciubotariu 			out_le32(&l2ana_reg->pfc[i].pfc_cfg,
2534c4390486SCodrin Ciubotariu 				 VSC9953_PFC_FC_QSGMII);
25356706b115SCodrin Ciubotariu 			out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i],
2536c4390486SCodrin Ciubotariu 				 VSC9953_MAC_FC_CFG_QSGMII);
25376706b115SCodrin Ciubotariu 		} else {
25386706b115SCodrin Ciubotariu 			out_le32(&l2ana_reg->pfc[i].pfc_cfg,
2539c4390486SCodrin Ciubotariu 				 VSC9953_PFC_FC);
25406706b115SCodrin Ciubotariu 			out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i],
2541c4390486SCodrin Ciubotariu 				 VSC9953_MAC_FC_CFG);
25426706b115SCodrin Ciubotariu 		}
254302c00f26SCodrin Ciubotariu 
254402c00f26SCodrin Ciubotariu 		l2dev_gmii_reg = (struct vsc9953_dev_gmii *)
254502c00f26SCodrin Ciubotariu 				 (VSC9953_OFFSET + VSC9953_DEV_GMII_OFFSET +
254602c00f26SCodrin Ciubotariu 				 T1040_SWITCH_GMII_DEV_OFFSET * i);
254702c00f26SCodrin Ciubotariu 
25486706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->port_mode.clock_cfg,
2549c4390486SCodrin Ciubotariu 			 VSC9953_CLOCK_CFG);
25506706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ena_cfg,
2551c4390486SCodrin Ciubotariu 			 VSC9953_MAC_ENA_CFG);
25526706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_mode_cfg,
2553c4390486SCodrin Ciubotariu 			 VSC9953_MAC_MODE_CFG);
25546706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ifg_cfg,
2555c4390486SCodrin Ciubotariu 			 VSC9953_MAC_IFG_CFG);
25566706b115SCodrin Ciubotariu 		/* mac_hdx_cfg varies with port id*/
2557c4390486SCodrin Ciubotariu 		hdx_cfg = VSC9953_MAC_HDX_CFG | (i << 16);
25586706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_hdx_cfg, hdx_cfg);
25596706b115SCodrin Ciubotariu 		out_le32(&l2sys_reg->sys.front_port_mode[i],
2560c4390486SCodrin Ciubotariu 			 VSC9953_FRONT_PORT_MODE);
2561fe91095bSCodrin Ciubotariu 		setbits_le32(&l2qsys_reg->sys.switch_port_mode[i],
2562c4390486SCodrin Ciubotariu 			     VSC9953_PORT_ENA);
25636706b115SCodrin Ciubotariu 		out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_maxlen_cfg,
2564c4390486SCodrin Ciubotariu 			 VSC9953_MAC_MAX_LEN);
25656706b115SCodrin Ciubotariu 		out_le32(&l2sys_reg->pause_cfg.pause_cfg[i],
2566c4390486SCodrin Ciubotariu 			 VSC9953_PAUSE_CFG);
25676706b115SCodrin Ciubotariu 		/* WAIT FOR 2 us*/
25686706b115SCodrin Ciubotariu 		udelay(2);
25696706b115SCodrin Ciubotariu 
25706706b115SCodrin Ciubotariu 		/* Initialize Lynx PHY Wrappers */
25716706b115SCodrin Ciubotariu 		phy_addr = 0;
25726706b115SCodrin Ciubotariu 		if (vsc9953_l2sw.port[i].enet_if ==
25736706b115SCodrin Ciubotariu 				PHY_INTERFACE_MODE_QSGMII)
25746706b115SCodrin Ciubotariu 			phy_addr = (i + 0x4) & 0x1F;
25756706b115SCodrin Ciubotariu 		else if (vsc9953_l2sw.port[i].enet_if ==
25766706b115SCodrin Ciubotariu 				PHY_INTERFACE_MODE_SGMII)
25776706b115SCodrin Ciubotariu 			phy_addr = (i + 1) & 0x1F;
25786706b115SCodrin Ciubotariu 
25796706b115SCodrin Ciubotariu 		if (phy_addr) {
25806706b115SCodrin Ciubotariu 			/* SGMII IF mode + AN enable */
25816706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
25826706b115SCodrin Ciubotariu 					   0x14, PHY_SGMII_IF_MODE_AN |
25836706b115SCodrin Ciubotariu 					   PHY_SGMII_IF_MODE_SGMII);
25846706b115SCodrin Ciubotariu 			/* Dev ability according to SGMII specification */
25856706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
25866706b115SCodrin Ciubotariu 					   0x4, PHY_SGMII_DEV_ABILITY_SGMII);
25876706b115SCodrin Ciubotariu 			/* Adjust link timer for SGMII
25886706b115SCodrin Ciubotariu 			 * 1.6 ms in units of 8 ns = 2 * 10^5 = 0x30d40
25896706b115SCodrin Ciubotariu 			 */
25906706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
25916706b115SCodrin Ciubotariu 					   0x13, 0x0003);
25926706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
25936706b115SCodrin Ciubotariu 					   0x12, 0x0d40);
25946706b115SCodrin Ciubotariu 			/* Restart AN */
25956706b115SCodrin Ciubotariu 			vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
25966706b115SCodrin Ciubotariu 					   0x0, PHY_SGMII_CR_DEF_VAL |
25976706b115SCodrin Ciubotariu 					   PHY_SGMII_CR_RESET_AN);
25986706b115SCodrin Ciubotariu 
25996706b115SCodrin Ciubotariu 			timeout = 50000;
26006706b115SCodrin Ciubotariu 			while ((vsc9953_mdio_read(&l2dev_gcb->mii_mng[0],
26016706b115SCodrin Ciubotariu 					phy_addr, 0x01) & 0x0020) && --timeout)
26026706b115SCodrin Ciubotariu 				udelay(1); /* wait for AN to complete */
26036706b115SCodrin Ciubotariu 			if (timeout == 0)
26046706b115SCodrin Ciubotariu 				debug("Timeout waiting for AN to complete\n");
26056706b115SCodrin Ciubotariu 		}
26066706b115SCodrin Ciubotariu 	}
26076706b115SCodrin Ciubotariu 
26089de05987SCodrin Ciubotariu 	vsc9953_default_configuration();
26099de05987SCodrin Ciubotariu 
261024a23debSCodrin Ciubotariu #ifdef CONFIG_CMD_ETHSW
261124a23debSCodrin Ciubotariu 	if (ethsw_define_functions(&vsc9953_cmd_func) < 0)
261224a23debSCodrin Ciubotariu 		debug("Unable to use \"ethsw\" commands\n");
261324a23debSCodrin Ciubotariu #endif
261424a23debSCodrin Ciubotariu 
26156706b115SCodrin Ciubotariu 	printf("VSC9953 L2 switch initialized\n");
26166706b115SCodrin Ciubotariu 	return;
26176706b115SCodrin Ciubotariu }
2618