// SPDX-License-Identifier: GPL-2.0+
/* Microchip Sparx5 Switch driver
 *
 * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
 */

#include "sparx5_main_regs.h"
#include "sparx5_main.h"

static int sparx5_vlant_set_mask(struct sparx5 *sparx5, u16 vid)
{
	u32 mask[3];

	/* Divide up mask in 32 bit words */
	bitmap_to_arr32(mask, sparx5->vlan_mask[vid], SPX5_PORTS);

	/* Output mask to respective registers */
	spx5_wr(mask[0], sparx5, ANA_L3_VLAN_MASK_CFG(vid));
	spx5_wr(mask[1], sparx5, ANA_L3_VLAN_MASK_CFG1(vid));
	spx5_wr(mask[2], sparx5, ANA_L3_VLAN_MASK_CFG2(vid));

	return 0;
}

void sparx5_vlan_init(struct sparx5 *sparx5)
{
	u16 vid;

	spx5_rmw(ANA_L3_VLAN_CTRL_VLAN_ENA_SET(1),
		 ANA_L3_VLAN_CTRL_VLAN_ENA,
		 sparx5,
		 ANA_L3_VLAN_CTRL);

	/* Map VLAN = FID */
	for (vid = NULL_VID; vid < VLAN_N_VID; vid++)
		spx5_rmw(ANA_L3_VLAN_CFG_VLAN_FID_SET(vid),
			 ANA_L3_VLAN_CFG_VLAN_FID,
			 sparx5,
			 ANA_L3_VLAN_CFG(vid));
}

void sparx5_vlan_port_setup(struct sparx5 *sparx5, int portno)
{
	struct sparx5_port *port = sparx5->ports[portno];

	/* Configure PVID */
	spx5_rmw(ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA_SET(0) |
		 ANA_CL_VLAN_CTRL_PORT_VID_SET(port->pvid),
		 ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA |
		 ANA_CL_VLAN_CTRL_PORT_VID,
		 sparx5,
		 ANA_CL_VLAN_CTRL(port->portno));
}

int sparx5_vlan_vid_add(struct sparx5_port *port, u16 vid, bool pvid,
			bool untagged)
{
	struct sparx5 *sparx5 = port->sparx5;
	int ret;

	/* Untagged egress vlan classification */
	if (untagged && port->vid != vid) {
		if (port->vid) {
			netdev_err(port->ndev,
				   "Port already has a native VLAN: %d\n",
				   port->vid);
			return -EBUSY;
		}
		port->vid = vid;
	}

	/* Make the port a member of the VLAN */
	set_bit(port->portno, sparx5->vlan_mask[vid]);
	ret = sparx5_vlant_set_mask(sparx5, vid);
	if (ret)
		return ret;

	/* Default ingress vlan classification */
	if (pvid)
		port->pvid = vid;

	sparx5_vlan_port_apply(sparx5, port);

	return 0;
}

int sparx5_vlan_vid_del(struct sparx5_port *port, u16 vid)
{
	struct sparx5 *sparx5 = port->sparx5;
	int ret;

	/* 8021q removes VID 0 on module unload for all interfaces
	 * with VLAN filtering feature. We need to keep it to receive
	 * untagged traffic.
	 */
	if (vid == 0)
		return 0;

	/* Stop the port from being a member of the vlan */
	clear_bit(port->portno, sparx5->vlan_mask[vid]);
	ret = sparx5_vlant_set_mask(sparx5, vid);
	if (ret)
		return ret;

	/* Ingress */
	if (port->pvid == vid)
		port->pvid = 0;

	/* Egress */
	if (port->vid == vid)
		port->vid = 0;

	sparx5_vlan_port_apply(sparx5, port);

	return 0;
}

void sparx5_pgid_update_mask(struct sparx5_port *port, int pgid, bool enable)
{
	struct sparx5 *sparx5 = port->sparx5;
	u32 val, mask;

	/* mask is spread across 3 registers x 32 bit */
	if (port->portno < 32) {
		mask = BIT(port->portno);
		val = enable ? mask : 0;
		spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG(pgid));
	} else if (port->portno < 64) {
		mask = BIT(port->portno - 32);
		val = enable ? mask : 0;
		spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG1(pgid));
	} else if (port->portno < SPX5_PORTS) {
		mask = BIT(port->portno - 64);
		val = enable ? mask : 0;
		spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG2(pgid));
	} else {
		netdev_err(port->ndev, "Invalid port no: %d\n", port->portno);
	}
}

void sparx5_pgid_read_mask(struct sparx5 *spx5, int pgid, u32 portmask[3])
{
	portmask[0] = spx5_rd(spx5, ANA_AC_PGID_CFG(pgid));
	portmask[1] = spx5_rd(spx5, ANA_AC_PGID_CFG1(pgid));
	portmask[2] = spx5_rd(spx5, ANA_AC_PGID_CFG2(pgid));
}

void sparx5_update_fwd(struct sparx5 *sparx5)
{
	DECLARE_BITMAP(workmask, SPX5_PORTS);
	u32 mask[3];
	int port;

	/* Divide up fwd mask in 32 bit words */
	bitmap_to_arr32(mask, sparx5->bridge_fwd_mask, SPX5_PORTS);

	/* Update flood masks */
	for (port = PGID_UC_FLOOD; port <= PGID_BCAST; port++) {
		spx5_wr(mask[0], sparx5, ANA_AC_PGID_CFG(port));
		spx5_wr(mask[1], sparx5, ANA_AC_PGID_CFG1(port));
		spx5_wr(mask[2], sparx5, ANA_AC_PGID_CFG2(port));
	}

	/* Update SRC masks */
	for (port = 0; port < SPX5_PORTS; port++) {
		if (test_bit(port, sparx5->bridge_fwd_mask)) {
			/* Allow to send to all bridged but self */
			bitmap_copy(workmask, sparx5->bridge_fwd_mask, SPX5_PORTS);
			clear_bit(port, workmask);
			bitmap_to_arr32(mask, workmask, SPX5_PORTS);
			spx5_wr(mask[0], sparx5, ANA_AC_SRC_CFG(port));
			spx5_wr(mask[1], sparx5, ANA_AC_SRC_CFG1(port));
			spx5_wr(mask[2], sparx5, ANA_AC_SRC_CFG2(port));
		} else {
			spx5_wr(0, sparx5, ANA_AC_SRC_CFG(port));
			spx5_wr(0, sparx5, ANA_AC_SRC_CFG1(port));
			spx5_wr(0, sparx5, ANA_AC_SRC_CFG2(port));
		}
	}

	/* Learning enabled only for bridged ports */
	bitmap_and(workmask, sparx5->bridge_fwd_mask,
		   sparx5->bridge_lrn_mask, SPX5_PORTS);
	bitmap_to_arr32(mask, workmask, SPX5_PORTS);

	/* Apply learning mask */
	spx5_wr(mask[0], sparx5, ANA_L2_AUTO_LRN_CFG);
	spx5_wr(mask[1], sparx5, ANA_L2_AUTO_LRN_CFG1);
	spx5_wr(mask[2], sparx5, ANA_L2_AUTO_LRN_CFG2);
}

void sparx5_vlan_port_apply(struct sparx5 *sparx5,
			    struct sparx5_port *port)

{
	u32 val;

	/* Configure PVID, vlan aware */
	val = ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA_SET(port->vlan_aware) |
		ANA_CL_VLAN_CTRL_VLAN_POP_CNT_SET(port->vlan_aware) |
		ANA_CL_VLAN_CTRL_PORT_VID_SET(port->pvid);
	spx5_wr(val, sparx5, ANA_CL_VLAN_CTRL(port->portno));

	val = 0;
	if (port->vlan_aware && !port->pvid)
		/* If port is vlan-aware and tagged, drop untagged and
		 * priority tagged frames.
		 */
		val = ANA_CL_VLAN_FILTER_CTRL_TAG_REQUIRED_ENA_SET(1) |
			ANA_CL_VLAN_FILTER_CTRL_PRIO_CTAG_DIS_SET(1) |
			ANA_CL_VLAN_FILTER_CTRL_PRIO_STAG_DIS_SET(1);
	spx5_wr(val, sparx5,
		ANA_CL_VLAN_FILTER_CTRL(port->portno, 0));

	/* Egress configuration (REW_TAG_CFG): VLAN tag type to 8021Q */
	val = REW_TAG_CTRL_TAG_TPID_CFG_SET(0);
	if (port->vlan_aware) {
		if (port->vid)
			/* Tag all frames except when VID == DEFAULT_VLAN */
			val |= REW_TAG_CTRL_TAG_CFG_SET(1);
		else
			val |= REW_TAG_CTRL_TAG_CFG_SET(3);
	}
	spx5_wr(val, sparx5, REW_TAG_CTRL(port->portno));

	/* Egress VID */
	spx5_rmw(REW_PORT_VLAN_CFG_PORT_VID_SET(port->vid),
		 REW_PORT_VLAN_CFG_PORT_VID,
		 sparx5,
		 REW_PORT_VLAN_CFG(port->portno));
}
