xref: /openbmc/linux/drivers/net/dsa/lantiq_gswip.c (revision 6ea1e677)
114fceff4SHauke Mehrtens // SPDX-License-Identifier: GPL-2.0
214fceff4SHauke Mehrtens /*
3a09d042bSAleksander Jan Bajkowski  * Lantiq / Intel GSWIP switch driver for VRX200, xRX300 and xRX330 SoCs
414fceff4SHauke Mehrtens  *
514fceff4SHauke Mehrtens  * Copyright (C) 2010 Lantiq Deutschland
614fceff4SHauke Mehrtens  * Copyright (C) 2012 John Crispin <john@phrozen.org>
78206e0ceSHauke Mehrtens  * Copyright (C) 2017 - 2019 Hauke Mehrtens <hauke@hauke-m.de>
88206e0ceSHauke Mehrtens  *
98206e0ceSHauke Mehrtens  * The VLAN and bridge model the GSWIP hardware uses does not directly
108206e0ceSHauke Mehrtens  * matches the model DSA uses.
118206e0ceSHauke Mehrtens  *
128206e0ceSHauke Mehrtens  * The hardware has 64 possible table entries for bridges with one VLAN
138206e0ceSHauke Mehrtens  * ID, one flow id and a list of ports for each bridge. All entries which
148206e0ceSHauke Mehrtens  * match the same flow ID are combined in the mac learning table, they
158206e0ceSHauke Mehrtens  * act as one global bridge.
168206e0ceSHauke Mehrtens  * The hardware does not support VLAN filter on the port, but on the
178206e0ceSHauke Mehrtens  * bridge, this driver converts the DSA model to the hardware.
188206e0ceSHauke Mehrtens  *
198206e0ceSHauke Mehrtens  * The CPU gets all the exception frames which do not match any forwarding
208206e0ceSHauke Mehrtens  * rule and the CPU port is also added to all bridges. This makes it possible
218206e0ceSHauke Mehrtens  * to handle all the special cases easily in software.
228206e0ceSHauke Mehrtens  * At the initialization the driver allocates one bridge table entry for
238206e0ceSHauke Mehrtens  * each switch port which is used when the port is used without an
248206e0ceSHauke Mehrtens  * explicit bridge. This prevents the frames from being forwarded
258206e0ceSHauke Mehrtens  * between all LAN ports by default.
2614fceff4SHauke Mehrtens  */
2714fceff4SHauke Mehrtens 
2814fceff4SHauke Mehrtens #include <linux/clk.h>
292a1828e3SMartin Blumenstingl #include <linux/delay.h>
3014fceff4SHauke Mehrtens #include <linux/etherdevice.h>
3114fceff4SHauke Mehrtens #include <linux/firmware.h>
3214fceff4SHauke Mehrtens #include <linux/if_bridge.h>
3314fceff4SHauke Mehrtens #include <linux/if_vlan.h>
3414fceff4SHauke Mehrtens #include <linux/iopoll.h>
3514fceff4SHauke Mehrtens #include <linux/mfd/syscon.h>
3614fceff4SHauke Mehrtens #include <linux/module.h>
3714fceff4SHauke Mehrtens #include <linux/of_mdio.h>
3814fceff4SHauke Mehrtens #include <linux/of_net.h>
3914fceff4SHauke Mehrtens #include <linux/of_platform.h>
4014fceff4SHauke Mehrtens #include <linux/phy.h>
4114fceff4SHauke Mehrtens #include <linux/phylink.h>
4214fceff4SHauke Mehrtens #include <linux/platform_device.h>
4314fceff4SHauke Mehrtens #include <linux/regmap.h>
4414fceff4SHauke Mehrtens #include <linux/reset.h>
4514fceff4SHauke Mehrtens #include <net/dsa.h>
4614fceff4SHauke Mehrtens #include <dt-bindings/mips/lantiq_rcu_gphy.h>
4714fceff4SHauke Mehrtens 
4814fceff4SHauke Mehrtens #include "lantiq_pce.h"
4914fceff4SHauke Mehrtens 
5014fceff4SHauke Mehrtens /* GSWIP MDIO Registers */
5114fceff4SHauke Mehrtens #define GSWIP_MDIO_GLOB			0x00
5214fceff4SHauke Mehrtens #define  GSWIP_MDIO_GLOB_ENABLE		BIT(15)
5314fceff4SHauke Mehrtens #define GSWIP_MDIO_CTRL			0x08
5414fceff4SHauke Mehrtens #define  GSWIP_MDIO_CTRL_BUSY		BIT(12)
5514fceff4SHauke Mehrtens #define  GSWIP_MDIO_CTRL_RD		BIT(11)
5614fceff4SHauke Mehrtens #define  GSWIP_MDIO_CTRL_WR		BIT(10)
5714fceff4SHauke Mehrtens #define  GSWIP_MDIO_CTRL_PHYAD_MASK	0x1f
5814fceff4SHauke Mehrtens #define  GSWIP_MDIO_CTRL_PHYAD_SHIFT	5
5914fceff4SHauke Mehrtens #define  GSWIP_MDIO_CTRL_REGAD_MASK	0x1f
6014fceff4SHauke Mehrtens #define GSWIP_MDIO_READ			0x09
6114fceff4SHauke Mehrtens #define GSWIP_MDIO_WRITE		0x0A
6214fceff4SHauke Mehrtens #define GSWIP_MDIO_MDC_CFG0		0x0B
6314fceff4SHauke Mehrtens #define GSWIP_MDIO_MDC_CFG1		0x0C
6414fceff4SHauke Mehrtens #define GSWIP_MDIO_PHYp(p)		(0x15 - (p))
6514fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_LINK_MASK	0x6000
6614fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_LINK_AUTO	0x0000
6714fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_LINK_DOWN	0x4000
6814fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_LINK_UP		0x2000
6914fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_SPEED_MASK	0x1800
7014fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_SPEED_AUTO	0x1800
7114fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_SPEED_M10	0x0000
7214fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_SPEED_M100	0x0800
7314fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_SPEED_G1	0x1000
7414fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_FDUP_MASK	0x0600
7514fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_FDUP_AUTO	0x0000
7614fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_FDUP_EN		0x0200
7714fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_FDUP_DIS	0x0600
7814fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_FCONTX_MASK	0x0180
7914fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_FCONTX_AUTO	0x0000
8014fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_FCONTX_EN	0x0100
8114fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_FCONTX_DIS	0x0180
8214fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_FCONRX_MASK	0x0060
8314fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_FCONRX_AUTO	0x0000
8414fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_FCONRX_EN	0x0020
8514fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_FCONRX_DIS	0x0060
8614fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_ADDR_MASK	0x001f
8714fceff4SHauke Mehrtens #define  GSWIP_MDIO_PHY_MASK		(GSWIP_MDIO_PHY_ADDR_MASK | \
8814fceff4SHauke Mehrtens 					 GSWIP_MDIO_PHY_FCONRX_MASK | \
8914fceff4SHauke Mehrtens 					 GSWIP_MDIO_PHY_FCONTX_MASK | \
9014fceff4SHauke Mehrtens 					 GSWIP_MDIO_PHY_LINK_MASK | \
9114fceff4SHauke Mehrtens 					 GSWIP_MDIO_PHY_SPEED_MASK | \
9214fceff4SHauke Mehrtens 					 GSWIP_MDIO_PHY_FDUP_MASK)
9314fceff4SHauke Mehrtens 
9414fceff4SHauke Mehrtens /* GSWIP MII Registers */
95709a3c9dSMartin Blumenstingl #define GSWIP_MII_CFGp(p)		(0x2 * (p))
964b592324SMartin Blumenstingl #define  GSWIP_MII_CFG_RESET		BIT(15)
9714fceff4SHauke Mehrtens #define  GSWIP_MII_CFG_EN		BIT(14)
984b592324SMartin Blumenstingl #define  GSWIP_MII_CFG_ISOLATE		BIT(13)
9914fceff4SHauke Mehrtens #define  GSWIP_MII_CFG_LDCLKDIS		BIT(12)
1004b592324SMartin Blumenstingl #define  GSWIP_MII_CFG_RGMII_IBS	BIT(8)
1014b592324SMartin Blumenstingl #define  GSWIP_MII_CFG_RMII_CLK		BIT(7)
10214fceff4SHauke Mehrtens #define  GSWIP_MII_CFG_MODE_MIIP	0x0
10314fceff4SHauke Mehrtens #define  GSWIP_MII_CFG_MODE_MIIM	0x1
10414fceff4SHauke Mehrtens #define  GSWIP_MII_CFG_MODE_RMIIP	0x2
10514fceff4SHauke Mehrtens #define  GSWIP_MII_CFG_MODE_RMIIM	0x3
10614fceff4SHauke Mehrtens #define  GSWIP_MII_CFG_MODE_RGMII	0x4
107a09d042bSAleksander Jan Bajkowski #define  GSWIP_MII_CFG_MODE_GMII	0x9
10814fceff4SHauke Mehrtens #define  GSWIP_MII_CFG_MODE_MASK	0xf
10914fceff4SHauke Mehrtens #define  GSWIP_MII_CFG_RATE_M2P5	0x00
11014fceff4SHauke Mehrtens #define  GSWIP_MII_CFG_RATE_M25	0x10
11114fceff4SHauke Mehrtens #define  GSWIP_MII_CFG_RATE_M125	0x20
11214fceff4SHauke Mehrtens #define  GSWIP_MII_CFG_RATE_M50	0x30
11314fceff4SHauke Mehrtens #define  GSWIP_MII_CFG_RATE_AUTO	0x40
11414fceff4SHauke Mehrtens #define  GSWIP_MII_CFG_RATE_MASK	0x70
11514fceff4SHauke Mehrtens #define GSWIP_MII_PCDU0			0x01
11614fceff4SHauke Mehrtens #define GSWIP_MII_PCDU1			0x03
11714fceff4SHauke Mehrtens #define GSWIP_MII_PCDU5			0x05
11814fceff4SHauke Mehrtens #define  GSWIP_MII_PCDU_TXDLY_MASK	GENMASK(2, 0)
11914fceff4SHauke Mehrtens #define  GSWIP_MII_PCDU_RXDLY_MASK	GENMASK(9, 7)
12014fceff4SHauke Mehrtens 
12114fceff4SHauke Mehrtens /* GSWIP Core Registers */
12214fceff4SHauke Mehrtens #define GSWIP_SWRES			0x000
12314fceff4SHauke Mehrtens #define  GSWIP_SWRES_R1			BIT(1)	/* GSWIP Software reset */
12414fceff4SHauke Mehrtens #define  GSWIP_SWRES_R0			BIT(0)	/* GSWIP Hardware reset */
12514fceff4SHauke Mehrtens #define GSWIP_VERSION			0x013
12614fceff4SHauke Mehrtens #define  GSWIP_VERSION_REV_SHIFT	0
12714fceff4SHauke Mehrtens #define  GSWIP_VERSION_REV_MASK		GENMASK(7, 0)
12814fceff4SHauke Mehrtens #define  GSWIP_VERSION_MOD_SHIFT	8
12914fceff4SHauke Mehrtens #define  GSWIP_VERSION_MOD_MASK		GENMASK(15, 8)
13014fceff4SHauke Mehrtens #define   GSWIP_VERSION_2_0		0x100
13114fceff4SHauke Mehrtens #define   GSWIP_VERSION_2_1		0x021
13214fceff4SHauke Mehrtens #define   GSWIP_VERSION_2_2		0x122
13314fceff4SHauke Mehrtens #define   GSWIP_VERSION_2_2_ETC		0x022
13414fceff4SHauke Mehrtens 
13514fceff4SHauke Mehrtens #define GSWIP_BM_RAM_VAL(x)		(0x043 - (x))
13614fceff4SHauke Mehrtens #define GSWIP_BM_RAM_ADDR		0x044
13714fceff4SHauke Mehrtens #define GSWIP_BM_RAM_CTRL		0x045
13814fceff4SHauke Mehrtens #define  GSWIP_BM_RAM_CTRL_BAS		BIT(15)
13914fceff4SHauke Mehrtens #define  GSWIP_BM_RAM_CTRL_OPMOD	BIT(5)
14014fceff4SHauke Mehrtens #define  GSWIP_BM_RAM_CTRL_ADDR_MASK	GENMASK(4, 0)
14114fceff4SHauke Mehrtens #define GSWIP_BM_QUEUE_GCTRL		0x04A
14214fceff4SHauke Mehrtens #define  GSWIP_BM_QUEUE_GCTRL_GL_MOD	BIT(10)
14314fceff4SHauke Mehrtens /* buffer management Port Configuration Register */
14414fceff4SHauke Mehrtens #define GSWIP_BM_PCFGp(p)		(0x080 + ((p) * 2))
14514fceff4SHauke Mehrtens #define  GSWIP_BM_PCFG_CNTEN		BIT(0)	/* RMON Counter Enable */
14614fceff4SHauke Mehrtens #define  GSWIP_BM_PCFG_IGCNT		BIT(1)	/* Ingres Special Tag RMON count */
14714fceff4SHauke Mehrtens /* buffer management Port Control Register */
14814fceff4SHauke Mehrtens #define GSWIP_BM_RMON_CTRLp(p)		(0x81 + ((p) * 2))
14914fceff4SHauke Mehrtens #define  GSWIP_BM_CTRL_RMON_RAM1_RES	BIT(0)	/* Software Reset for RMON RAM 1 */
15014fceff4SHauke Mehrtens #define  GSWIP_BM_CTRL_RMON_RAM2_RES	BIT(1)	/* Software Reset for RMON RAM 2 */
15114fceff4SHauke Mehrtens 
15214fceff4SHauke Mehrtens /* PCE */
15314fceff4SHauke Mehrtens #define GSWIP_PCE_TBL_KEY(x)		(0x447 - (x))
15414fceff4SHauke Mehrtens #define GSWIP_PCE_TBL_MASK		0x448
15514fceff4SHauke Mehrtens #define GSWIP_PCE_TBL_VAL(x)		(0x44D - (x))
15614fceff4SHauke Mehrtens #define GSWIP_PCE_TBL_ADDR		0x44E
15714fceff4SHauke Mehrtens #define GSWIP_PCE_TBL_CTRL		0x44F
15814fceff4SHauke Mehrtens #define  GSWIP_PCE_TBL_CTRL_BAS		BIT(15)
15914fceff4SHauke Mehrtens #define  GSWIP_PCE_TBL_CTRL_TYPE	BIT(13)
16014fceff4SHauke Mehrtens #define  GSWIP_PCE_TBL_CTRL_VLD		BIT(12)
16114fceff4SHauke Mehrtens #define  GSWIP_PCE_TBL_CTRL_KEYFORM	BIT(11)
16214fceff4SHauke Mehrtens #define  GSWIP_PCE_TBL_CTRL_GMAP_MASK	GENMASK(10, 7)
16314fceff4SHauke Mehrtens #define  GSWIP_PCE_TBL_CTRL_OPMOD_MASK	GENMASK(6, 5)
16414fceff4SHauke Mehrtens #define  GSWIP_PCE_TBL_CTRL_OPMOD_ADRD	0x00
16514fceff4SHauke Mehrtens #define  GSWIP_PCE_TBL_CTRL_OPMOD_ADWR	0x20
16614fceff4SHauke Mehrtens #define  GSWIP_PCE_TBL_CTRL_OPMOD_KSRD	0x40
16714fceff4SHauke Mehrtens #define  GSWIP_PCE_TBL_CTRL_OPMOD_KSWR	0x60
16814fceff4SHauke Mehrtens #define  GSWIP_PCE_TBL_CTRL_ADDR_MASK	GENMASK(4, 0)
16914fceff4SHauke Mehrtens #define GSWIP_PCE_PMAP1			0x453	/* Monitoring port map */
17014fceff4SHauke Mehrtens #define GSWIP_PCE_PMAP2			0x454	/* Default Multicast port map */
17114fceff4SHauke Mehrtens #define GSWIP_PCE_PMAP3			0x455	/* Default Unknown Unicast port map */
17214fceff4SHauke Mehrtens #define GSWIP_PCE_GCTRL_0		0x456
1738206e0ceSHauke Mehrtens #define  GSWIP_PCE_GCTRL_0_MTFL		BIT(0)  /* MAC Table Flushing */
17414fceff4SHauke Mehrtens #define  GSWIP_PCE_GCTRL_0_MC_VALID	BIT(3)
17514fceff4SHauke Mehrtens #define  GSWIP_PCE_GCTRL_0_VLAN		BIT(14) /* VLAN aware Switching */
17614fceff4SHauke Mehrtens #define GSWIP_PCE_GCTRL_1		0x457
17714fceff4SHauke Mehrtens #define  GSWIP_PCE_GCTRL_1_MAC_GLOCK	BIT(2)	/* MAC Address table lock */
17814fceff4SHauke Mehrtens #define  GSWIP_PCE_GCTRL_1_MAC_GLOCK_MOD	BIT(3) /* Mac address table lock forwarding mode */
17914fceff4SHauke Mehrtens #define GSWIP_PCE_PCTRL_0p(p)		(0x480 + ((p) * 0xA))
1808206e0ceSHauke Mehrtens #define  GSWIP_PCE_PCTRL_0_TVM		BIT(5)	/* Transparent VLAN mode */
1818206e0ceSHauke Mehrtens #define  GSWIP_PCE_PCTRL_0_VREP		BIT(6)	/* VLAN Replace Mode */
1828206e0ceSHauke Mehrtens #define  GSWIP_PCE_PCTRL_0_INGRESS	BIT(11)	/* Accept special tag in ingress */
18314fceff4SHauke Mehrtens #define  GSWIP_PCE_PCTRL_0_PSTATE_LISTEN	0x0
18414fceff4SHauke Mehrtens #define  GSWIP_PCE_PCTRL_0_PSTATE_RX		0x1
18514fceff4SHauke Mehrtens #define  GSWIP_PCE_PCTRL_0_PSTATE_TX		0x2
18614fceff4SHauke Mehrtens #define  GSWIP_PCE_PCTRL_0_PSTATE_LEARNING	0x3
18714fceff4SHauke Mehrtens #define  GSWIP_PCE_PCTRL_0_PSTATE_FORWARDING	0x7
18814fceff4SHauke Mehrtens #define  GSWIP_PCE_PCTRL_0_PSTATE_MASK	GENMASK(2, 0)
1898206e0ceSHauke Mehrtens #define GSWIP_PCE_VCTRL(p)		(0x485 + ((p) * 0xA))
1908206e0ceSHauke Mehrtens #define  GSWIP_PCE_VCTRL_UVR		BIT(0)	/* Unknown VLAN Rule */
1918206e0ceSHauke Mehrtens #define  GSWIP_PCE_VCTRL_VIMR		BIT(3)	/* VLAN Ingress Member violation rule */
1928206e0ceSHauke Mehrtens #define  GSWIP_PCE_VCTRL_VEMR		BIT(4)	/* VLAN Egress Member violation rule */
1938206e0ceSHauke Mehrtens #define  GSWIP_PCE_VCTRL_VSR		BIT(5)	/* VLAN Security */
1948206e0ceSHauke Mehrtens #define  GSWIP_PCE_VCTRL_VID0		BIT(6)	/* Priority Tagged Rule */
1958206e0ceSHauke Mehrtens #define GSWIP_PCE_DEFPVID(p)		(0x486 + ((p) * 0xA))
19614fceff4SHauke Mehrtens 
19714fceff4SHauke Mehrtens #define GSWIP_MAC_FLEN			0x8C5
1983e9005beSMartin Blumenstingl #define GSWIP_MAC_CTRL_0p(p)		(0x903 + ((p) * 0xC))
1993e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_PADEN		BIT(8)
2003e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_FCS_EN	BIT(7)
2013e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_FCON_MASK	0x0070
2023e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_FCON_AUTO	0x0000
2033e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_FCON_RX	0x0010
2043e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_FCON_TX	0x0020
2053e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_FCON_RXTX	0x0030
2063e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_FCON_NONE	0x0040
2073e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_FDUP_MASK	0x000C
2083e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_FDUP_AUTO	0x0000
2093e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_FDUP_EN	0x0004
2103e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_FDUP_DIS	0x000C
2113e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_GMII_MASK	0x0003
2123e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_GMII_AUTO	0x0000
2133e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_GMII_MII	0x0001
2143e9005beSMartin Blumenstingl #define  GSWIP_MAC_CTRL_0_GMII_RGMII	0x0002
21514fceff4SHauke Mehrtens #define GSWIP_MAC_CTRL_2p(p)		(0x905 + ((p) * 0xC))
216c40bb4feSAleksander Jan Bajkowski #define GSWIP_MAC_CTRL_2_LCHKL		BIT(2) /* Frame Length Check Long Enable */
21714fceff4SHauke Mehrtens #define GSWIP_MAC_CTRL_2_MLEN		BIT(3) /* Maximum Untagged Frame Lnegth */
21814fceff4SHauke Mehrtens 
21914fceff4SHauke Mehrtens /* Ethernet Switch Fetch DMA Port Control Register */
22014fceff4SHauke Mehrtens #define GSWIP_FDMA_PCTRLp(p)		(0xA80 + ((p) * 0x6))
22114fceff4SHauke Mehrtens #define  GSWIP_FDMA_PCTRL_EN		BIT(0)	/* FDMA Port Enable */
22214fceff4SHauke Mehrtens #define  GSWIP_FDMA_PCTRL_STEN		BIT(1)	/* Special Tag Insertion Enable */
22314fceff4SHauke Mehrtens #define  GSWIP_FDMA_PCTRL_VLANMOD_MASK	GENMASK(4, 3)	/* VLAN Modification Control */
22414fceff4SHauke Mehrtens #define  GSWIP_FDMA_PCTRL_VLANMOD_SHIFT	3	/* VLAN Modification Control */
22514fceff4SHauke Mehrtens #define  GSWIP_FDMA_PCTRL_VLANMOD_DIS	(0x0 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT)
22614fceff4SHauke Mehrtens #define  GSWIP_FDMA_PCTRL_VLANMOD_PRIO	(0x1 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT)
22714fceff4SHauke Mehrtens #define  GSWIP_FDMA_PCTRL_VLANMOD_ID	(0x2 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT)
22814fceff4SHauke Mehrtens #define  GSWIP_FDMA_PCTRL_VLANMOD_BOTH	(0x3 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT)
22914fceff4SHauke Mehrtens 
23014fceff4SHauke Mehrtens /* Ethernet Switch Store DMA Port Control Register */
23114fceff4SHauke Mehrtens #define GSWIP_SDMA_PCTRLp(p)		(0xBC0 + ((p) * 0x6))
23214fceff4SHauke Mehrtens #define  GSWIP_SDMA_PCTRL_EN		BIT(0)	/* SDMA Port Enable */
23314fceff4SHauke Mehrtens #define  GSWIP_SDMA_PCTRL_FCEN		BIT(1)	/* Flow Control Enable */
23466d26280SAleksander Jan Bajkowski #define  GSWIP_SDMA_PCTRL_PAUFWD	BIT(3)	/* Pause Frame Forwarding */
23514fceff4SHauke Mehrtens 
2368206e0ceSHauke Mehrtens #define GSWIP_TABLE_ACTIVE_VLAN		0x01
2378206e0ceSHauke Mehrtens #define GSWIP_TABLE_VLAN_MAPPING	0x02
23845813481SHauke Mehrtens #define GSWIP_TABLE_MAC_BRIDGE		0x0b
23945813481SHauke Mehrtens #define  GSWIP_TABLE_MAC_BRIDGE_STATIC	0x01	/* Static not, aging entry */
2408206e0ceSHauke Mehrtens 
24114fceff4SHauke Mehrtens #define XRX200_GPHY_FW_ALIGN	(16 * 1024)
24214fceff4SHauke Mehrtens 
243c40bb4feSAleksander Jan Bajkowski /* Maximum packet size supported by the switch. In theory this should be 10240,
244c40bb4feSAleksander Jan Bajkowski  * but long packets currently cause lock-ups with an MTU of over 2526. Medium
245c40bb4feSAleksander Jan Bajkowski  * packets are sometimes dropped (e.g. TCP over 2477, UDP over 2516-2519, ICMP
246c40bb4feSAleksander Jan Bajkowski  * over 2526), hence an MTU value of 2400 seems safe. This issue only affects
247c40bb4feSAleksander Jan Bajkowski  * packet reception. This is probably caused by the PPA engine, which is on the
248c40bb4feSAleksander Jan Bajkowski  * RX part of the device. Packet transmission works properly up to 10240.
249c40bb4feSAleksander Jan Bajkowski  */
250c40bb4feSAleksander Jan Bajkowski #define GSWIP_MAX_PACKET_LENGTH	2400
251c40bb4feSAleksander Jan Bajkowski 
25214fceff4SHauke Mehrtens struct gswip_hw_info {
25314fceff4SHauke Mehrtens 	int max_ports;
25414fceff4SHauke Mehrtens 	int cpu_port;
255a09d042bSAleksander Jan Bajkowski 	const struct dsa_switch_ops *ops;
25614fceff4SHauke Mehrtens };
25714fceff4SHauke Mehrtens 
25814fceff4SHauke Mehrtens struct xway_gphy_match_data {
25914fceff4SHauke Mehrtens 	char *fe_firmware_name;
26014fceff4SHauke Mehrtens 	char *ge_firmware_name;
26114fceff4SHauke Mehrtens };
26214fceff4SHauke Mehrtens 
26314fceff4SHauke Mehrtens struct gswip_gphy_fw {
26414fceff4SHauke Mehrtens 	struct clk *clk_gate;
26514fceff4SHauke Mehrtens 	struct reset_control *reset;
26614fceff4SHauke Mehrtens 	u32 fw_addr_offset;
26714fceff4SHauke Mehrtens 	char *fw_name;
26814fceff4SHauke Mehrtens };
26914fceff4SHauke Mehrtens 
2708206e0ceSHauke Mehrtens struct gswip_vlan {
2718206e0ceSHauke Mehrtens 	struct net_device *bridge;
2728206e0ceSHauke Mehrtens 	u16 vid;
2738206e0ceSHauke Mehrtens 	u8 fid;
2748206e0ceSHauke Mehrtens };
2758206e0ceSHauke Mehrtens 
27614fceff4SHauke Mehrtens struct gswip_priv {
27714fceff4SHauke Mehrtens 	__iomem void *gswip;
27814fceff4SHauke Mehrtens 	__iomem void *mdio;
27914fceff4SHauke Mehrtens 	__iomem void *mii;
28014fceff4SHauke Mehrtens 	const struct gswip_hw_info *hw_info;
28114fceff4SHauke Mehrtens 	const struct xway_gphy_match_data *gphy_fw_name_cfg;
28214fceff4SHauke Mehrtens 	struct dsa_switch *ds;
28314fceff4SHauke Mehrtens 	struct device *dev;
28414fceff4SHauke Mehrtens 	struct regmap *rcu_regmap;
2858206e0ceSHauke Mehrtens 	struct gswip_vlan vlans[64];
28614fceff4SHauke Mehrtens 	int num_gphy_fw;
28714fceff4SHauke Mehrtens 	struct gswip_gphy_fw *gphy_fw;
2889bbb1c05SHauke Mehrtens 	u32 port_vlan_filter;
289cf231b43SVladimir Oltean 	struct mutex pce_table_lock;
29014fceff4SHauke Mehrtens };
29114fceff4SHauke Mehrtens 
2928206e0ceSHauke Mehrtens struct gswip_pce_table_entry {
2938206e0ceSHauke Mehrtens 	u16 index;      // PCE_TBL_ADDR.ADDR = pData->table_index
2948206e0ceSHauke Mehrtens 	u16 table;      // PCE_TBL_CTRL.ADDR = pData->table
2958206e0ceSHauke Mehrtens 	u16 key[8];
2968206e0ceSHauke Mehrtens 	u16 val[5];
2978206e0ceSHauke Mehrtens 	u16 mask;
2988206e0ceSHauke Mehrtens 	u8 gmap;
2998206e0ceSHauke Mehrtens 	bool type;
3008206e0ceSHauke Mehrtens 	bool valid;
3018206e0ceSHauke Mehrtens 	bool key_mode;
3028206e0ceSHauke Mehrtens };
3038206e0ceSHauke Mehrtens 
30414fceff4SHauke Mehrtens struct gswip_rmon_cnt_desc {
30514fceff4SHauke Mehrtens 	unsigned int size;
30614fceff4SHauke Mehrtens 	unsigned int offset;
30714fceff4SHauke Mehrtens 	const char *name;
30814fceff4SHauke Mehrtens };
30914fceff4SHauke Mehrtens 
31014fceff4SHauke Mehrtens #define MIB_DESC(_size, _offset, _name) {.size = _size, .offset = _offset, .name = _name}
31114fceff4SHauke Mehrtens 
31214fceff4SHauke Mehrtens static const struct gswip_rmon_cnt_desc gswip_rmon_cnt[] = {
31314fceff4SHauke Mehrtens 	/** Receive Packet Count (only packets that are accepted and not discarded). */
31414fceff4SHauke Mehrtens 	MIB_DESC(1, 0x1F, "RxGoodPkts"),
31514fceff4SHauke Mehrtens 	MIB_DESC(1, 0x23, "RxUnicastPkts"),
31614fceff4SHauke Mehrtens 	MIB_DESC(1, 0x22, "RxMulticastPkts"),
31714fceff4SHauke Mehrtens 	MIB_DESC(1, 0x21, "RxFCSErrorPkts"),
31814fceff4SHauke Mehrtens 	MIB_DESC(1, 0x1D, "RxUnderSizeGoodPkts"),
31914fceff4SHauke Mehrtens 	MIB_DESC(1, 0x1E, "RxUnderSizeErrorPkts"),
32014fceff4SHauke Mehrtens 	MIB_DESC(1, 0x1B, "RxOversizeGoodPkts"),
32114fceff4SHauke Mehrtens 	MIB_DESC(1, 0x1C, "RxOversizeErrorPkts"),
32214fceff4SHauke Mehrtens 	MIB_DESC(1, 0x20, "RxGoodPausePkts"),
32314fceff4SHauke Mehrtens 	MIB_DESC(1, 0x1A, "RxAlignErrorPkts"),
32414fceff4SHauke Mehrtens 	MIB_DESC(1, 0x12, "Rx64BytePkts"),
32514fceff4SHauke Mehrtens 	MIB_DESC(1, 0x13, "Rx127BytePkts"),
32614fceff4SHauke Mehrtens 	MIB_DESC(1, 0x14, "Rx255BytePkts"),
32714fceff4SHauke Mehrtens 	MIB_DESC(1, 0x15, "Rx511BytePkts"),
32814fceff4SHauke Mehrtens 	MIB_DESC(1, 0x16, "Rx1023BytePkts"),
32914fceff4SHauke Mehrtens 	/** Receive Size 1024-1522 (or more, if configured) Packet Count. */
33014fceff4SHauke Mehrtens 	MIB_DESC(1, 0x17, "RxMaxBytePkts"),
33114fceff4SHauke Mehrtens 	MIB_DESC(1, 0x18, "RxDroppedPkts"),
33214fceff4SHauke Mehrtens 	MIB_DESC(1, 0x19, "RxFilteredPkts"),
33314fceff4SHauke Mehrtens 	MIB_DESC(2, 0x24, "RxGoodBytes"),
33414fceff4SHauke Mehrtens 	MIB_DESC(2, 0x26, "RxBadBytes"),
33514fceff4SHauke Mehrtens 	MIB_DESC(1, 0x11, "TxAcmDroppedPkts"),
33614fceff4SHauke Mehrtens 	MIB_DESC(1, 0x0C, "TxGoodPkts"),
33714fceff4SHauke Mehrtens 	MIB_DESC(1, 0x06, "TxUnicastPkts"),
33814fceff4SHauke Mehrtens 	MIB_DESC(1, 0x07, "TxMulticastPkts"),
33914fceff4SHauke Mehrtens 	MIB_DESC(1, 0x00, "Tx64BytePkts"),
34014fceff4SHauke Mehrtens 	MIB_DESC(1, 0x01, "Tx127BytePkts"),
34114fceff4SHauke Mehrtens 	MIB_DESC(1, 0x02, "Tx255BytePkts"),
34214fceff4SHauke Mehrtens 	MIB_DESC(1, 0x03, "Tx511BytePkts"),
34314fceff4SHauke Mehrtens 	MIB_DESC(1, 0x04, "Tx1023BytePkts"),
34414fceff4SHauke Mehrtens 	/** Transmit Size 1024-1522 (or more, if configured) Packet Count. */
34514fceff4SHauke Mehrtens 	MIB_DESC(1, 0x05, "TxMaxBytePkts"),
34614fceff4SHauke Mehrtens 	MIB_DESC(1, 0x08, "TxSingleCollCount"),
34714fceff4SHauke Mehrtens 	MIB_DESC(1, 0x09, "TxMultCollCount"),
34814fceff4SHauke Mehrtens 	MIB_DESC(1, 0x0A, "TxLateCollCount"),
34914fceff4SHauke Mehrtens 	MIB_DESC(1, 0x0B, "TxExcessCollCount"),
35014fceff4SHauke Mehrtens 	MIB_DESC(1, 0x0D, "TxPauseCount"),
35114fceff4SHauke Mehrtens 	MIB_DESC(1, 0x10, "TxDroppedPkts"),
35214fceff4SHauke Mehrtens 	MIB_DESC(2, 0x0E, "TxGoodBytes"),
35314fceff4SHauke Mehrtens };
35414fceff4SHauke Mehrtens 
gswip_switch_r(struct gswip_priv * priv,u32 offset)35514fceff4SHauke Mehrtens static u32 gswip_switch_r(struct gswip_priv *priv, u32 offset)
35614fceff4SHauke Mehrtens {
35714fceff4SHauke Mehrtens 	return __raw_readl(priv->gswip + (offset * 4));
35814fceff4SHauke Mehrtens }
35914fceff4SHauke Mehrtens 
gswip_switch_w(struct gswip_priv * priv,u32 val,u32 offset)36014fceff4SHauke Mehrtens static void gswip_switch_w(struct gswip_priv *priv, u32 val, u32 offset)
36114fceff4SHauke Mehrtens {
36214fceff4SHauke Mehrtens 	__raw_writel(val, priv->gswip + (offset * 4));
36314fceff4SHauke Mehrtens }
36414fceff4SHauke Mehrtens 
gswip_switch_mask(struct gswip_priv * priv,u32 clear,u32 set,u32 offset)36514fceff4SHauke Mehrtens static void gswip_switch_mask(struct gswip_priv *priv, u32 clear, u32 set,
36614fceff4SHauke Mehrtens 			      u32 offset)
36714fceff4SHauke Mehrtens {
36814fceff4SHauke Mehrtens 	u32 val = gswip_switch_r(priv, offset);
36914fceff4SHauke Mehrtens 
37014fceff4SHauke Mehrtens 	val &= ~(clear);
37114fceff4SHauke Mehrtens 	val |= set;
37214fceff4SHauke Mehrtens 	gswip_switch_w(priv, val, offset);
37314fceff4SHauke Mehrtens }
37414fceff4SHauke Mehrtens 
gswip_switch_r_timeout(struct gswip_priv * priv,u32 offset,u32 cleared)37514fceff4SHauke Mehrtens static u32 gswip_switch_r_timeout(struct gswip_priv *priv, u32 offset,
37614fceff4SHauke Mehrtens 				  u32 cleared)
37714fceff4SHauke Mehrtens {
37814fceff4SHauke Mehrtens 	u32 val;
37914fceff4SHauke Mehrtens 
38014fceff4SHauke Mehrtens 	return readx_poll_timeout(__raw_readl, priv->gswip + (offset * 4), val,
38114fceff4SHauke Mehrtens 				  (val & cleared) == 0, 20, 50000);
38214fceff4SHauke Mehrtens }
38314fceff4SHauke Mehrtens 
gswip_mdio_r(struct gswip_priv * priv,u32 offset)38414fceff4SHauke Mehrtens static u32 gswip_mdio_r(struct gswip_priv *priv, u32 offset)
38514fceff4SHauke Mehrtens {
38614fceff4SHauke Mehrtens 	return __raw_readl(priv->mdio + (offset * 4));
38714fceff4SHauke Mehrtens }
38814fceff4SHauke Mehrtens 
gswip_mdio_w(struct gswip_priv * priv,u32 val,u32 offset)38914fceff4SHauke Mehrtens static void gswip_mdio_w(struct gswip_priv *priv, u32 val, u32 offset)
39014fceff4SHauke Mehrtens {
39114fceff4SHauke Mehrtens 	__raw_writel(val, priv->mdio + (offset * 4));
39214fceff4SHauke Mehrtens }
39314fceff4SHauke Mehrtens 
gswip_mdio_mask(struct gswip_priv * priv,u32 clear,u32 set,u32 offset)39414fceff4SHauke Mehrtens static void gswip_mdio_mask(struct gswip_priv *priv, u32 clear, u32 set,
39514fceff4SHauke Mehrtens 			    u32 offset)
39614fceff4SHauke Mehrtens {
39714fceff4SHauke Mehrtens 	u32 val = gswip_mdio_r(priv, offset);
39814fceff4SHauke Mehrtens 
39914fceff4SHauke Mehrtens 	val &= ~(clear);
40014fceff4SHauke Mehrtens 	val |= set;
40114fceff4SHauke Mehrtens 	gswip_mdio_w(priv, val, offset);
40214fceff4SHauke Mehrtens }
40314fceff4SHauke Mehrtens 
gswip_mii_r(struct gswip_priv * priv,u32 offset)40414fceff4SHauke Mehrtens static u32 gswip_mii_r(struct gswip_priv *priv, u32 offset)
40514fceff4SHauke Mehrtens {
40614fceff4SHauke Mehrtens 	return __raw_readl(priv->mii + (offset * 4));
40714fceff4SHauke Mehrtens }
40814fceff4SHauke Mehrtens 
gswip_mii_w(struct gswip_priv * priv,u32 val,u32 offset)40914fceff4SHauke Mehrtens static void gswip_mii_w(struct gswip_priv *priv, u32 val, u32 offset)
41014fceff4SHauke Mehrtens {
41114fceff4SHauke Mehrtens 	__raw_writel(val, priv->mii + (offset * 4));
41214fceff4SHauke Mehrtens }
41314fceff4SHauke Mehrtens 
gswip_mii_mask(struct gswip_priv * priv,u32 clear,u32 set,u32 offset)41414fceff4SHauke Mehrtens static void gswip_mii_mask(struct gswip_priv *priv, u32 clear, u32 set,
41514fceff4SHauke Mehrtens 			   u32 offset)
41614fceff4SHauke Mehrtens {
41714fceff4SHauke Mehrtens 	u32 val = gswip_mii_r(priv, offset);
41814fceff4SHauke Mehrtens 
41914fceff4SHauke Mehrtens 	val &= ~(clear);
42014fceff4SHauke Mehrtens 	val |= set;
42114fceff4SHauke Mehrtens 	gswip_mii_w(priv, val, offset);
42214fceff4SHauke Mehrtens }
42314fceff4SHauke Mehrtens 
gswip_mii_mask_cfg(struct gswip_priv * priv,u32 clear,u32 set,int port)42414fceff4SHauke Mehrtens static void gswip_mii_mask_cfg(struct gswip_priv *priv, u32 clear, u32 set,
42514fceff4SHauke Mehrtens 			       int port)
42614fceff4SHauke Mehrtens {
427709a3c9dSMartin Blumenstingl 	/* There's no MII_CFG register for the CPU port */
428709a3c9dSMartin Blumenstingl 	if (!dsa_is_cpu_port(priv->ds, port))
429709a3c9dSMartin Blumenstingl 		gswip_mii_mask(priv, clear, set, GSWIP_MII_CFGp(port));
43014fceff4SHauke Mehrtens }
43114fceff4SHauke Mehrtens 
gswip_mii_mask_pcdu(struct gswip_priv * priv,u32 clear,u32 set,int port)43214fceff4SHauke Mehrtens static void gswip_mii_mask_pcdu(struct gswip_priv *priv, u32 clear, u32 set,
43314fceff4SHauke Mehrtens 				int port)
43414fceff4SHauke Mehrtens {
43514fceff4SHauke Mehrtens 	switch (port) {
43614fceff4SHauke Mehrtens 	case 0:
43714fceff4SHauke Mehrtens 		gswip_mii_mask(priv, clear, set, GSWIP_MII_PCDU0);
43814fceff4SHauke Mehrtens 		break;
43914fceff4SHauke Mehrtens 	case 1:
44014fceff4SHauke Mehrtens 		gswip_mii_mask(priv, clear, set, GSWIP_MII_PCDU1);
44114fceff4SHauke Mehrtens 		break;
44214fceff4SHauke Mehrtens 	case 5:
44314fceff4SHauke Mehrtens 		gswip_mii_mask(priv, clear, set, GSWIP_MII_PCDU5);
44414fceff4SHauke Mehrtens 		break;
44514fceff4SHauke Mehrtens 	}
44614fceff4SHauke Mehrtens }
44714fceff4SHauke Mehrtens 
gswip_mdio_poll(struct gswip_priv * priv)44814fceff4SHauke Mehrtens static int gswip_mdio_poll(struct gswip_priv *priv)
44914fceff4SHauke Mehrtens {
45014fceff4SHauke Mehrtens 	int cnt = 100;
45114fceff4SHauke Mehrtens 
45214fceff4SHauke Mehrtens 	while (likely(cnt--)) {
45314fceff4SHauke Mehrtens 		u32 ctrl = gswip_mdio_r(priv, GSWIP_MDIO_CTRL);
45414fceff4SHauke Mehrtens 
45514fceff4SHauke Mehrtens 		if ((ctrl & GSWIP_MDIO_CTRL_BUSY) == 0)
45614fceff4SHauke Mehrtens 			return 0;
45714fceff4SHauke Mehrtens 		usleep_range(20, 40);
45814fceff4SHauke Mehrtens 	}
45914fceff4SHauke Mehrtens 
46014fceff4SHauke Mehrtens 	return -ETIMEDOUT;
46114fceff4SHauke Mehrtens }
46214fceff4SHauke Mehrtens 
gswip_mdio_wr(struct mii_bus * bus,int addr,int reg,u16 val)46314fceff4SHauke Mehrtens static int gswip_mdio_wr(struct mii_bus *bus, int addr, int reg, u16 val)
46414fceff4SHauke Mehrtens {
46514fceff4SHauke Mehrtens 	struct gswip_priv *priv = bus->priv;
46614fceff4SHauke Mehrtens 	int err;
46714fceff4SHauke Mehrtens 
46814fceff4SHauke Mehrtens 	err = gswip_mdio_poll(priv);
46914fceff4SHauke Mehrtens 	if (err) {
47014fceff4SHauke Mehrtens 		dev_err(&bus->dev, "waiting for MDIO bus busy timed out\n");
47114fceff4SHauke Mehrtens 		return err;
47214fceff4SHauke Mehrtens 	}
47314fceff4SHauke Mehrtens 
47414fceff4SHauke Mehrtens 	gswip_mdio_w(priv, val, GSWIP_MDIO_WRITE);
47514fceff4SHauke Mehrtens 	gswip_mdio_w(priv, GSWIP_MDIO_CTRL_BUSY | GSWIP_MDIO_CTRL_WR |
47614fceff4SHauke Mehrtens 		((addr & GSWIP_MDIO_CTRL_PHYAD_MASK) << GSWIP_MDIO_CTRL_PHYAD_SHIFT) |
47714fceff4SHauke Mehrtens 		(reg & GSWIP_MDIO_CTRL_REGAD_MASK),
47814fceff4SHauke Mehrtens 		GSWIP_MDIO_CTRL);
47914fceff4SHauke Mehrtens 
48014fceff4SHauke Mehrtens 	return 0;
48114fceff4SHauke Mehrtens }
48214fceff4SHauke Mehrtens 
gswip_mdio_rd(struct mii_bus * bus,int addr,int reg)48314fceff4SHauke Mehrtens static int gswip_mdio_rd(struct mii_bus *bus, int addr, int reg)
48414fceff4SHauke Mehrtens {
48514fceff4SHauke Mehrtens 	struct gswip_priv *priv = bus->priv;
48614fceff4SHauke Mehrtens 	int err;
48714fceff4SHauke Mehrtens 
48814fceff4SHauke Mehrtens 	err = gswip_mdio_poll(priv);
48914fceff4SHauke Mehrtens 	if (err) {
49014fceff4SHauke Mehrtens 		dev_err(&bus->dev, "waiting for MDIO bus busy timed out\n");
49114fceff4SHauke Mehrtens 		return err;
49214fceff4SHauke Mehrtens 	}
49314fceff4SHauke Mehrtens 
49414fceff4SHauke Mehrtens 	gswip_mdio_w(priv, GSWIP_MDIO_CTRL_BUSY | GSWIP_MDIO_CTRL_RD |
49514fceff4SHauke Mehrtens 		((addr & GSWIP_MDIO_CTRL_PHYAD_MASK) << GSWIP_MDIO_CTRL_PHYAD_SHIFT) |
49614fceff4SHauke Mehrtens 		(reg & GSWIP_MDIO_CTRL_REGAD_MASK),
49714fceff4SHauke Mehrtens 		GSWIP_MDIO_CTRL);
49814fceff4SHauke Mehrtens 
49914fceff4SHauke Mehrtens 	err = gswip_mdio_poll(priv);
50014fceff4SHauke Mehrtens 	if (err) {
50114fceff4SHauke Mehrtens 		dev_err(&bus->dev, "waiting for MDIO bus busy timed out\n");
50214fceff4SHauke Mehrtens 		return err;
50314fceff4SHauke Mehrtens 	}
50414fceff4SHauke Mehrtens 
50514fceff4SHauke Mehrtens 	return gswip_mdio_r(priv, GSWIP_MDIO_READ);
50614fceff4SHauke Mehrtens }
50714fceff4SHauke Mehrtens 
gswip_mdio(struct gswip_priv * priv,struct device_node * mdio_np)50814fceff4SHauke Mehrtens static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np)
50914fceff4SHauke Mehrtens {
51014fceff4SHauke Mehrtens 	struct dsa_switch *ds = priv->ds;
5110d120dfbSVladimir Oltean 	int err;
51214fceff4SHauke Mehrtens 
5130d120dfbSVladimir Oltean 	ds->slave_mii_bus = mdiobus_alloc();
51414fceff4SHauke Mehrtens 	if (!ds->slave_mii_bus)
51514fceff4SHauke Mehrtens 		return -ENOMEM;
51614fceff4SHauke Mehrtens 
51714fceff4SHauke Mehrtens 	ds->slave_mii_bus->priv = priv;
51814fceff4SHauke Mehrtens 	ds->slave_mii_bus->read = gswip_mdio_rd;
51914fceff4SHauke Mehrtens 	ds->slave_mii_bus->write = gswip_mdio_wr;
52014fceff4SHauke Mehrtens 	ds->slave_mii_bus->name = "lantiq,xrx200-mdio";
52114fceff4SHauke Mehrtens 	snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s-mii",
52214fceff4SHauke Mehrtens 		 dev_name(priv->dev));
52314fceff4SHauke Mehrtens 	ds->slave_mii_bus->parent = priv->dev;
52414fceff4SHauke Mehrtens 	ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask;
52514fceff4SHauke Mehrtens 
5260d120dfbSVladimir Oltean 	err = of_mdiobus_register(ds->slave_mii_bus, mdio_np);
5270d120dfbSVladimir Oltean 	if (err)
5280d120dfbSVladimir Oltean 		mdiobus_free(ds->slave_mii_bus);
5290d120dfbSVladimir Oltean 
5300d120dfbSVladimir Oltean 	return err;
53114fceff4SHauke Mehrtens }
53214fceff4SHauke Mehrtens 
gswip_pce_table_entry_read(struct gswip_priv * priv,struct gswip_pce_table_entry * tbl)5338206e0ceSHauke Mehrtens static int gswip_pce_table_entry_read(struct gswip_priv *priv,
5348206e0ceSHauke Mehrtens 				      struct gswip_pce_table_entry *tbl)
5358206e0ceSHauke Mehrtens {
5368206e0ceSHauke Mehrtens 	int i;
5378206e0ceSHauke Mehrtens 	int err;
5388206e0ceSHauke Mehrtens 	u16 crtl;
5398206e0ceSHauke Mehrtens 	u16 addr_mode = tbl->key_mode ? GSWIP_PCE_TBL_CTRL_OPMOD_KSRD :
5408206e0ceSHauke Mehrtens 					GSWIP_PCE_TBL_CTRL_OPMOD_ADRD;
5418206e0ceSHauke Mehrtens 
542cf231b43SVladimir Oltean 	mutex_lock(&priv->pce_table_lock);
543cf231b43SVladimir Oltean 
5448206e0ceSHauke Mehrtens 	err = gswip_switch_r_timeout(priv, GSWIP_PCE_TBL_CTRL,
5458206e0ceSHauke Mehrtens 				     GSWIP_PCE_TBL_CTRL_BAS);
546cf231b43SVladimir Oltean 	if (err) {
547cf231b43SVladimir Oltean 		mutex_unlock(&priv->pce_table_lock);
5488206e0ceSHauke Mehrtens 		return err;
549cf231b43SVladimir Oltean 	}
5508206e0ceSHauke Mehrtens 
5518206e0ceSHauke Mehrtens 	gswip_switch_w(priv, tbl->index, GSWIP_PCE_TBL_ADDR);
5528206e0ceSHauke Mehrtens 	gswip_switch_mask(priv, GSWIP_PCE_TBL_CTRL_ADDR_MASK |
5538206e0ceSHauke Mehrtens 				GSWIP_PCE_TBL_CTRL_OPMOD_MASK,
5548206e0ceSHauke Mehrtens 			  tbl->table | addr_mode | GSWIP_PCE_TBL_CTRL_BAS,
5558206e0ceSHauke Mehrtens 			  GSWIP_PCE_TBL_CTRL);
5568206e0ceSHauke Mehrtens 
5578206e0ceSHauke Mehrtens 	err = gswip_switch_r_timeout(priv, GSWIP_PCE_TBL_CTRL,
5588206e0ceSHauke Mehrtens 				     GSWIP_PCE_TBL_CTRL_BAS);
559cf231b43SVladimir Oltean 	if (err) {
560cf231b43SVladimir Oltean 		mutex_unlock(&priv->pce_table_lock);
5618206e0ceSHauke Mehrtens 		return err;
562cf231b43SVladimir Oltean 	}
5638206e0ceSHauke Mehrtens 
5648206e0ceSHauke Mehrtens 	for (i = 0; i < ARRAY_SIZE(tbl->key); i++)
5658206e0ceSHauke Mehrtens 		tbl->key[i] = gswip_switch_r(priv, GSWIP_PCE_TBL_KEY(i));
5668206e0ceSHauke Mehrtens 
5678206e0ceSHauke Mehrtens 	for (i = 0; i < ARRAY_SIZE(tbl->val); i++)
5688206e0ceSHauke Mehrtens 		tbl->val[i] = gswip_switch_r(priv, GSWIP_PCE_TBL_VAL(i));
5698206e0ceSHauke Mehrtens 
5708206e0ceSHauke Mehrtens 	tbl->mask = gswip_switch_r(priv, GSWIP_PCE_TBL_MASK);
5718206e0ceSHauke Mehrtens 
5728206e0ceSHauke Mehrtens 	crtl = gswip_switch_r(priv, GSWIP_PCE_TBL_CTRL);
5738206e0ceSHauke Mehrtens 
5748206e0ceSHauke Mehrtens 	tbl->type = !!(crtl & GSWIP_PCE_TBL_CTRL_TYPE);
5758206e0ceSHauke Mehrtens 	tbl->valid = !!(crtl & GSWIP_PCE_TBL_CTRL_VLD);
5768206e0ceSHauke Mehrtens 	tbl->gmap = (crtl & GSWIP_PCE_TBL_CTRL_GMAP_MASK) >> 7;
5778206e0ceSHauke Mehrtens 
578cf231b43SVladimir Oltean 	mutex_unlock(&priv->pce_table_lock);
579cf231b43SVladimir Oltean 
5808206e0ceSHauke Mehrtens 	return 0;
5818206e0ceSHauke Mehrtens }
5828206e0ceSHauke Mehrtens 
gswip_pce_table_entry_write(struct gswip_priv * priv,struct gswip_pce_table_entry * tbl)5838206e0ceSHauke Mehrtens static int gswip_pce_table_entry_write(struct gswip_priv *priv,
5848206e0ceSHauke Mehrtens 				       struct gswip_pce_table_entry *tbl)
5858206e0ceSHauke Mehrtens {
5868206e0ceSHauke Mehrtens 	int i;
5878206e0ceSHauke Mehrtens 	int err;
5888206e0ceSHauke Mehrtens 	u16 crtl;
5898206e0ceSHauke Mehrtens 	u16 addr_mode = tbl->key_mode ? GSWIP_PCE_TBL_CTRL_OPMOD_KSWR :
5908206e0ceSHauke Mehrtens 					GSWIP_PCE_TBL_CTRL_OPMOD_ADWR;
5918206e0ceSHauke Mehrtens 
592cf231b43SVladimir Oltean 	mutex_lock(&priv->pce_table_lock);
593cf231b43SVladimir Oltean 
5948206e0ceSHauke Mehrtens 	err = gswip_switch_r_timeout(priv, GSWIP_PCE_TBL_CTRL,
5958206e0ceSHauke Mehrtens 				     GSWIP_PCE_TBL_CTRL_BAS);
596cf231b43SVladimir Oltean 	if (err) {
597cf231b43SVladimir Oltean 		mutex_unlock(&priv->pce_table_lock);
5988206e0ceSHauke Mehrtens 		return err;
599cf231b43SVladimir Oltean 	}
6008206e0ceSHauke Mehrtens 
6018206e0ceSHauke Mehrtens 	gswip_switch_w(priv, tbl->index, GSWIP_PCE_TBL_ADDR);
6028206e0ceSHauke Mehrtens 	gswip_switch_mask(priv, GSWIP_PCE_TBL_CTRL_ADDR_MASK |
6038206e0ceSHauke Mehrtens 				GSWIP_PCE_TBL_CTRL_OPMOD_MASK,
6048206e0ceSHauke Mehrtens 			  tbl->table | addr_mode,
6058206e0ceSHauke Mehrtens 			  GSWIP_PCE_TBL_CTRL);
6068206e0ceSHauke Mehrtens 
6078206e0ceSHauke Mehrtens 	for (i = 0; i < ARRAY_SIZE(tbl->key); i++)
6088206e0ceSHauke Mehrtens 		gswip_switch_w(priv, tbl->key[i], GSWIP_PCE_TBL_KEY(i));
6098206e0ceSHauke Mehrtens 
6108206e0ceSHauke Mehrtens 	for (i = 0; i < ARRAY_SIZE(tbl->val); i++)
6118206e0ceSHauke Mehrtens 		gswip_switch_w(priv, tbl->val[i], GSWIP_PCE_TBL_VAL(i));
6128206e0ceSHauke Mehrtens 
6138206e0ceSHauke Mehrtens 	gswip_switch_mask(priv, GSWIP_PCE_TBL_CTRL_ADDR_MASK |
6148206e0ceSHauke Mehrtens 				GSWIP_PCE_TBL_CTRL_OPMOD_MASK,
6158206e0ceSHauke Mehrtens 			  tbl->table | addr_mode,
6168206e0ceSHauke Mehrtens 			  GSWIP_PCE_TBL_CTRL);
6178206e0ceSHauke Mehrtens 
6188206e0ceSHauke Mehrtens 	gswip_switch_w(priv, tbl->mask, GSWIP_PCE_TBL_MASK);
6198206e0ceSHauke Mehrtens 
6208206e0ceSHauke Mehrtens 	crtl = gswip_switch_r(priv, GSWIP_PCE_TBL_CTRL);
6218206e0ceSHauke Mehrtens 	crtl &= ~(GSWIP_PCE_TBL_CTRL_TYPE | GSWIP_PCE_TBL_CTRL_VLD |
6228206e0ceSHauke Mehrtens 		  GSWIP_PCE_TBL_CTRL_GMAP_MASK);
6238206e0ceSHauke Mehrtens 	if (tbl->type)
6248206e0ceSHauke Mehrtens 		crtl |= GSWIP_PCE_TBL_CTRL_TYPE;
6258206e0ceSHauke Mehrtens 	if (tbl->valid)
6268206e0ceSHauke Mehrtens 		crtl |= GSWIP_PCE_TBL_CTRL_VLD;
6278206e0ceSHauke Mehrtens 	crtl |= (tbl->gmap << 7) & GSWIP_PCE_TBL_CTRL_GMAP_MASK;
6288206e0ceSHauke Mehrtens 	crtl |= GSWIP_PCE_TBL_CTRL_BAS;
6298206e0ceSHauke Mehrtens 	gswip_switch_w(priv, crtl, GSWIP_PCE_TBL_CTRL);
6308206e0ceSHauke Mehrtens 
631cf231b43SVladimir Oltean 	err = gswip_switch_r_timeout(priv, GSWIP_PCE_TBL_CTRL,
6328206e0ceSHauke Mehrtens 				     GSWIP_PCE_TBL_CTRL_BAS);
633cf231b43SVladimir Oltean 
634cf231b43SVladimir Oltean 	mutex_unlock(&priv->pce_table_lock);
635cf231b43SVladimir Oltean 
636cf231b43SVladimir Oltean 	return err;
6378206e0ceSHauke Mehrtens }
6388206e0ceSHauke Mehrtens 
6398206e0ceSHauke Mehrtens /* Add the LAN port into a bridge with the CPU port by
6408206e0ceSHauke Mehrtens  * default. This prevents automatic forwarding of
6418206e0ceSHauke Mehrtens  * packages between the LAN ports when no explicit
6428206e0ceSHauke Mehrtens  * bridge is configured.
6438206e0ceSHauke Mehrtens  */
gswip_add_single_port_br(struct gswip_priv * priv,int port,bool add)6448206e0ceSHauke Mehrtens static int gswip_add_single_port_br(struct gswip_priv *priv, int port, bool add)
6458206e0ceSHauke Mehrtens {
6468206e0ceSHauke Mehrtens 	struct gswip_pce_table_entry vlan_active = {0,};
6478206e0ceSHauke Mehrtens 	struct gswip_pce_table_entry vlan_mapping = {0,};
6488206e0ceSHauke Mehrtens 	unsigned int cpu_port = priv->hw_info->cpu_port;
6498206e0ceSHauke Mehrtens 	unsigned int max_ports = priv->hw_info->max_ports;
6508206e0ceSHauke Mehrtens 	int err;
6518206e0ceSHauke Mehrtens 
6528206e0ceSHauke Mehrtens 	if (port >= max_ports) {
6538206e0ceSHauke Mehrtens 		dev_err(priv->dev, "single port for %i supported\n", port);
6548206e0ceSHauke Mehrtens 		return -EIO;
6558206e0ceSHauke Mehrtens 	}
6568206e0ceSHauke Mehrtens 
6578206e0ceSHauke Mehrtens 	vlan_active.index = port + 1;
6588206e0ceSHauke Mehrtens 	vlan_active.table = GSWIP_TABLE_ACTIVE_VLAN;
6598206e0ceSHauke Mehrtens 	vlan_active.key[0] = 0; /* vid */
6608206e0ceSHauke Mehrtens 	vlan_active.val[0] = port + 1 /* fid */;
6618206e0ceSHauke Mehrtens 	vlan_active.valid = add;
6628206e0ceSHauke Mehrtens 	err = gswip_pce_table_entry_write(priv, &vlan_active);
6638206e0ceSHauke Mehrtens 	if (err) {
6648206e0ceSHauke Mehrtens 		dev_err(priv->dev, "failed to write active VLAN: %d\n", err);
6658206e0ceSHauke Mehrtens 		return err;
6668206e0ceSHauke Mehrtens 	}
6678206e0ceSHauke Mehrtens 
6688206e0ceSHauke Mehrtens 	if (!add)
6698206e0ceSHauke Mehrtens 		return 0;
6708206e0ceSHauke Mehrtens 
6718206e0ceSHauke Mehrtens 	vlan_mapping.index = port + 1;
6728206e0ceSHauke Mehrtens 	vlan_mapping.table = GSWIP_TABLE_VLAN_MAPPING;
6738206e0ceSHauke Mehrtens 	vlan_mapping.val[0] = 0 /* vid */;
6748206e0ceSHauke Mehrtens 	vlan_mapping.val[1] = BIT(port) | BIT(cpu_port);
6758206e0ceSHauke Mehrtens 	vlan_mapping.val[2] = 0;
6768206e0ceSHauke Mehrtens 	err = gswip_pce_table_entry_write(priv, &vlan_mapping);
6778206e0ceSHauke Mehrtens 	if (err) {
6788206e0ceSHauke Mehrtens 		dev_err(priv->dev, "failed to write VLAN mapping: %d\n", err);
6798206e0ceSHauke Mehrtens 		return err;
6808206e0ceSHauke Mehrtens 	}
6818206e0ceSHauke Mehrtens 
6828206e0ceSHauke Mehrtens 	return 0;
6838206e0ceSHauke Mehrtens }
6848206e0ceSHauke Mehrtens 
gswip_port_enable(struct dsa_switch * ds,int port,struct phy_device * phydev)68514fceff4SHauke Mehrtens static int gswip_port_enable(struct dsa_switch *ds, int port,
68614fceff4SHauke Mehrtens 			     struct phy_device *phydev)
68714fceff4SHauke Mehrtens {
68814fceff4SHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
6898206e0ceSHauke Mehrtens 	int err;
6908206e0ceSHauke Mehrtens 
69174be4babSVivien Didelot 	if (!dsa_is_user_port(ds, port))
69274be4babSVivien Didelot 		return 0;
69374be4babSVivien Didelot 
6948206e0ceSHauke Mehrtens 	if (!dsa_is_cpu_port(ds, port)) {
6958206e0ceSHauke Mehrtens 		err = gswip_add_single_port_br(priv, port, true);
6968206e0ceSHauke Mehrtens 		if (err)
6978206e0ceSHauke Mehrtens 			return err;
6988206e0ceSHauke Mehrtens 	}
69914fceff4SHauke Mehrtens 
70014fceff4SHauke Mehrtens 	/* RMON Counter Enable for port */
70114fceff4SHauke Mehrtens 	gswip_switch_w(priv, GSWIP_BM_PCFG_CNTEN, GSWIP_BM_PCFGp(port));
70214fceff4SHauke Mehrtens 
70314fceff4SHauke Mehrtens 	/* enable port fetch/store dma & VLAN Modification */
70414fceff4SHauke Mehrtens 	gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_EN |
70514fceff4SHauke Mehrtens 				   GSWIP_FDMA_PCTRL_VLANMOD_BOTH,
70614fceff4SHauke Mehrtens 			 GSWIP_FDMA_PCTRLp(port));
70714fceff4SHauke Mehrtens 	gswip_switch_mask(priv, 0, GSWIP_SDMA_PCTRL_EN,
70814fceff4SHauke Mehrtens 			  GSWIP_SDMA_PCTRLp(port));
70914fceff4SHauke Mehrtens 
71014fceff4SHauke Mehrtens 	if (!dsa_is_cpu_port(ds, port)) {
7113e9005beSMartin Blumenstingl 		u32 mdio_phy = 0;
71214fceff4SHauke Mehrtens 
7133e9005beSMartin Blumenstingl 		if (phydev)
7143e9005beSMartin Blumenstingl 			mdio_phy = phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK;
7153e9005beSMartin Blumenstingl 
7163e9005beSMartin Blumenstingl 		gswip_mdio_mask(priv, GSWIP_MDIO_PHY_ADDR_MASK, mdio_phy,
7173e9005beSMartin Blumenstingl 				GSWIP_MDIO_PHYp(port));
71814fceff4SHauke Mehrtens 	}
71914fceff4SHauke Mehrtens 
72014fceff4SHauke Mehrtens 	return 0;
72114fceff4SHauke Mehrtens }
72214fceff4SHauke Mehrtens 
gswip_port_disable(struct dsa_switch * ds,int port)72375104db0SAndrew Lunn static void gswip_port_disable(struct dsa_switch *ds, int port)
72414fceff4SHauke Mehrtens {
72514fceff4SHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
72614fceff4SHauke Mehrtens 
72774be4babSVivien Didelot 	if (!dsa_is_user_port(ds, port))
72874be4babSVivien Didelot 		return;
72974be4babSVivien Didelot 
73014fceff4SHauke Mehrtens 	gswip_switch_mask(priv, GSWIP_FDMA_PCTRL_EN, 0,
73114fceff4SHauke Mehrtens 			  GSWIP_FDMA_PCTRLp(port));
73214fceff4SHauke Mehrtens 	gswip_switch_mask(priv, GSWIP_SDMA_PCTRL_EN, 0,
73314fceff4SHauke Mehrtens 			  GSWIP_SDMA_PCTRLp(port));
73414fceff4SHauke Mehrtens }
73514fceff4SHauke Mehrtens 
gswip_pce_load_microcode(struct gswip_priv * priv)73614fceff4SHauke Mehrtens static int gswip_pce_load_microcode(struct gswip_priv *priv)
73714fceff4SHauke Mehrtens {
73814fceff4SHauke Mehrtens 	int i;
73914fceff4SHauke Mehrtens 	int err;
74014fceff4SHauke Mehrtens 
74114fceff4SHauke Mehrtens 	gswip_switch_mask(priv, GSWIP_PCE_TBL_CTRL_ADDR_MASK |
74214fceff4SHauke Mehrtens 				GSWIP_PCE_TBL_CTRL_OPMOD_MASK,
74314fceff4SHauke Mehrtens 			  GSWIP_PCE_TBL_CTRL_OPMOD_ADWR, GSWIP_PCE_TBL_CTRL);
74414fceff4SHauke Mehrtens 	gswip_switch_w(priv, 0, GSWIP_PCE_TBL_MASK);
74514fceff4SHauke Mehrtens 
74614fceff4SHauke Mehrtens 	for (i = 0; i < ARRAY_SIZE(gswip_pce_microcode); i++) {
74714fceff4SHauke Mehrtens 		gswip_switch_w(priv, i, GSWIP_PCE_TBL_ADDR);
74814fceff4SHauke Mehrtens 		gswip_switch_w(priv, gswip_pce_microcode[i].val_0,
74914fceff4SHauke Mehrtens 			       GSWIP_PCE_TBL_VAL(0));
75014fceff4SHauke Mehrtens 		gswip_switch_w(priv, gswip_pce_microcode[i].val_1,
75114fceff4SHauke Mehrtens 			       GSWIP_PCE_TBL_VAL(1));
75214fceff4SHauke Mehrtens 		gswip_switch_w(priv, gswip_pce_microcode[i].val_2,
75314fceff4SHauke Mehrtens 			       GSWIP_PCE_TBL_VAL(2));
75414fceff4SHauke Mehrtens 		gswip_switch_w(priv, gswip_pce_microcode[i].val_3,
75514fceff4SHauke Mehrtens 			       GSWIP_PCE_TBL_VAL(3));
75614fceff4SHauke Mehrtens 
75714fceff4SHauke Mehrtens 		/* start the table access: */
75814fceff4SHauke Mehrtens 		gswip_switch_mask(priv, 0, GSWIP_PCE_TBL_CTRL_BAS,
75914fceff4SHauke Mehrtens 				  GSWIP_PCE_TBL_CTRL);
76014fceff4SHauke Mehrtens 		err = gswip_switch_r_timeout(priv, GSWIP_PCE_TBL_CTRL,
76114fceff4SHauke Mehrtens 					     GSWIP_PCE_TBL_CTRL_BAS);
76214fceff4SHauke Mehrtens 		if (err)
76314fceff4SHauke Mehrtens 			return err;
76414fceff4SHauke Mehrtens 	}
76514fceff4SHauke Mehrtens 
76614fceff4SHauke Mehrtens 	/* tell the switch that the microcode is loaded */
76714fceff4SHauke Mehrtens 	gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_0_MC_VALID,
76814fceff4SHauke Mehrtens 			  GSWIP_PCE_GCTRL_0);
76914fceff4SHauke Mehrtens 
77014fceff4SHauke Mehrtens 	return 0;
77114fceff4SHauke Mehrtens }
77214fceff4SHauke Mehrtens 
gswip_port_vlan_filtering(struct dsa_switch * ds,int port,bool vlan_filtering,struct netlink_ext_ack * extack)7738206e0ceSHauke Mehrtens static int gswip_port_vlan_filtering(struct dsa_switch *ds, int port,
77489153ed6SVladimir Oltean 				     bool vlan_filtering,
77589153ed6SVladimir Oltean 				     struct netlink_ext_ack *extack)
7768206e0ceSHauke Mehrtens {
77741fb0cf1SVladimir Oltean 	struct net_device *bridge = dsa_port_bridge_dev_get(dsa_to_port(ds, port));
7788206e0ceSHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
7799bbb1c05SHauke Mehrtens 
7809bbb1c05SHauke Mehrtens 	/* Do not allow changing the VLAN filtering options while in bridge */
78189153ed6SVladimir Oltean 	if (bridge && !!(priv->port_vlan_filter & BIT(port)) != vlan_filtering) {
78289153ed6SVladimir Oltean 		NL_SET_ERR_MSG_MOD(extack,
78389153ed6SVladimir Oltean 				   "Dynamic toggling of vlan_filtering not supported");
7849bbb1c05SHauke Mehrtens 		return -EIO;
78589153ed6SVladimir Oltean 	}
7868206e0ceSHauke Mehrtens 
7878206e0ceSHauke Mehrtens 	if (vlan_filtering) {
7888206e0ceSHauke Mehrtens 		/* Use port based VLAN tag */
7898206e0ceSHauke Mehrtens 		gswip_switch_mask(priv,
7908206e0ceSHauke Mehrtens 				  GSWIP_PCE_VCTRL_VSR,
7918206e0ceSHauke Mehrtens 				  GSWIP_PCE_VCTRL_UVR | GSWIP_PCE_VCTRL_VIMR |
7928206e0ceSHauke Mehrtens 				  GSWIP_PCE_VCTRL_VEMR,
7938206e0ceSHauke Mehrtens 				  GSWIP_PCE_VCTRL(port));
7948206e0ceSHauke Mehrtens 		gswip_switch_mask(priv, GSWIP_PCE_PCTRL_0_TVM, 0,
7958206e0ceSHauke Mehrtens 				  GSWIP_PCE_PCTRL_0p(port));
7968206e0ceSHauke Mehrtens 	} else {
7978206e0ceSHauke Mehrtens 		/* Use port based VLAN tag */
7988206e0ceSHauke Mehrtens 		gswip_switch_mask(priv,
7998206e0ceSHauke Mehrtens 				  GSWIP_PCE_VCTRL_UVR | GSWIP_PCE_VCTRL_VIMR |
8008206e0ceSHauke Mehrtens 				  GSWIP_PCE_VCTRL_VEMR,
8018206e0ceSHauke Mehrtens 				  GSWIP_PCE_VCTRL_VSR,
8028206e0ceSHauke Mehrtens 				  GSWIP_PCE_VCTRL(port));
8038206e0ceSHauke Mehrtens 		gswip_switch_mask(priv, 0, GSWIP_PCE_PCTRL_0_TVM,
8048206e0ceSHauke Mehrtens 				  GSWIP_PCE_PCTRL_0p(port));
8058206e0ceSHauke Mehrtens 	}
8068206e0ceSHauke Mehrtens 
8078206e0ceSHauke Mehrtens 	return 0;
8088206e0ceSHauke Mehrtens }
8098206e0ceSHauke Mehrtens 
gswip_setup(struct dsa_switch * ds)81014fceff4SHauke Mehrtens static int gswip_setup(struct dsa_switch *ds)
81114fceff4SHauke Mehrtens {
81214fceff4SHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
81314fceff4SHauke Mehrtens 	unsigned int cpu_port = priv->hw_info->cpu_port;
81414fceff4SHauke Mehrtens 	int i;
81514fceff4SHauke Mehrtens 	int err;
81614fceff4SHauke Mehrtens 
81714fceff4SHauke Mehrtens 	gswip_switch_w(priv, GSWIP_SWRES_R0, GSWIP_SWRES);
81814fceff4SHauke Mehrtens 	usleep_range(5000, 10000);
81914fceff4SHauke Mehrtens 	gswip_switch_w(priv, 0, GSWIP_SWRES);
82014fceff4SHauke Mehrtens 
82114fceff4SHauke Mehrtens 	/* disable port fetch/store dma on all ports */
8228206e0ceSHauke Mehrtens 	for (i = 0; i < priv->hw_info->max_ports; i++) {
82375104db0SAndrew Lunn 		gswip_port_disable(ds, i);
82489153ed6SVladimir Oltean 		gswip_port_vlan_filtering(ds, i, false, NULL);
8258206e0ceSHauke Mehrtens 	}
82614fceff4SHauke Mehrtens 
82714fceff4SHauke Mehrtens 	/* enable Switch */
82814fceff4SHauke Mehrtens 	gswip_mdio_mask(priv, 0, GSWIP_MDIO_GLOB_ENABLE, GSWIP_MDIO_GLOB);
82914fceff4SHauke Mehrtens 
83014fceff4SHauke Mehrtens 	err = gswip_pce_load_microcode(priv);
83114fceff4SHauke Mehrtens 	if (err) {
83214fceff4SHauke Mehrtens 		dev_err(priv->dev, "writing PCE microcode failed, %i", err);
83314fceff4SHauke Mehrtens 		return err;
83414fceff4SHauke Mehrtens 	}
83514fceff4SHauke Mehrtens 
83614fceff4SHauke Mehrtens 	/* Default unknown Broadcast/Multicast/Unicast port maps */
83714fceff4SHauke Mehrtens 	gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP1);
83814fceff4SHauke Mehrtens 	gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP2);
83914fceff4SHauke Mehrtens 	gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP3);
84014fceff4SHauke Mehrtens 
8413e9005beSMartin Blumenstingl 	/* Deactivate MDIO PHY auto polling. Some PHYs as the AR8030 have an
8423e9005beSMartin Blumenstingl 	 * interoperability problem with this auto polling mechanism because
8433e9005beSMartin Blumenstingl 	 * their status registers think that the link is in a different state
8443e9005beSMartin Blumenstingl 	 * than it actually is. For the AR8030 it has the BMSR_ESTATEN bit set
8453e9005beSMartin Blumenstingl 	 * as well as ESTATUS_1000_TFULL and ESTATUS_1000_XFULL. This makes the
8463e9005beSMartin Blumenstingl 	 * auto polling state machine consider the link being negotiated with
8473e9005beSMartin Blumenstingl 	 * 1Gbit/s. Since the PHY itself is a Fast Ethernet RMII PHY this leads
8483e9005beSMartin Blumenstingl 	 * to the switch port being completely dead (RX and TX are both not
8493e9005beSMartin Blumenstingl 	 * working).
8503e9005beSMartin Blumenstingl 	 * Also with various other PHY / port combinations (PHY11G GPHY, PHY22F
8513e9005beSMartin Blumenstingl 	 * GPHY, external RGMII PEF7071/7072) any traffic would stop. Sometimes
8523e9005beSMartin Blumenstingl 	 * it would work fine for a few minutes to hours and then stop, on
8533e9005beSMartin Blumenstingl 	 * other device it would no traffic could be sent or received at all.
8543e9005beSMartin Blumenstingl 	 * Testing shows that when PHY auto polling is disabled these problems
8553e9005beSMartin Blumenstingl 	 * go away.
8563e9005beSMartin Blumenstingl 	 */
85714fceff4SHauke Mehrtens 	gswip_mdio_w(priv, 0x0, GSWIP_MDIO_MDC_CFG0);
8583e9005beSMartin Blumenstingl 
85914fceff4SHauke Mehrtens 	/* Configure the MDIO Clock 2.5 MHz */
86014fceff4SHauke Mehrtens 	gswip_mdio_mask(priv, 0xff, 0x09, GSWIP_MDIO_MDC_CFG1);
86114fceff4SHauke Mehrtens 
8624b592324SMartin Blumenstingl 	/* Disable the xMII interface and clear it's isolation bit */
863709a3c9dSMartin Blumenstingl 	for (i = 0; i < priv->hw_info->max_ports; i++)
8644b592324SMartin Blumenstingl 		gswip_mii_mask_cfg(priv,
8654b592324SMartin Blumenstingl 				   GSWIP_MII_CFG_EN | GSWIP_MII_CFG_ISOLATE,
8664b592324SMartin Blumenstingl 				   0, i);
86714fceff4SHauke Mehrtens 
86814fceff4SHauke Mehrtens 	/* enable special tag insertion on cpu port */
86914fceff4SHauke Mehrtens 	gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_STEN,
87014fceff4SHauke Mehrtens 			  GSWIP_FDMA_PCTRLp(cpu_port));
87114fceff4SHauke Mehrtens 
87230d89383SHauke Mehrtens 	/* accept special tag in ingress direction */
87330d89383SHauke Mehrtens 	gswip_switch_mask(priv, 0, GSWIP_PCE_PCTRL_0_INGRESS,
87430d89383SHauke Mehrtens 			  GSWIP_PCE_PCTRL_0p(cpu_port));
87530d89383SHauke Mehrtens 
87614fceff4SHauke Mehrtens 	gswip_switch_mask(priv, 0, GSWIP_BM_QUEUE_GCTRL_GL_MOD,
87714fceff4SHauke Mehrtens 			  GSWIP_BM_QUEUE_GCTRL);
87814fceff4SHauke Mehrtens 
87914fceff4SHauke Mehrtens 	/* VLAN aware Switching */
88014fceff4SHauke Mehrtens 	gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_0_VLAN, GSWIP_PCE_GCTRL_0);
88114fceff4SHauke Mehrtens 
8828206e0ceSHauke Mehrtens 	/* Flush MAC Table */
8838206e0ceSHauke Mehrtens 	gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_0_MTFL, GSWIP_PCE_GCTRL_0);
8848206e0ceSHauke Mehrtens 
8858206e0ceSHauke Mehrtens 	err = gswip_switch_r_timeout(priv, GSWIP_PCE_GCTRL_0,
8868206e0ceSHauke Mehrtens 				     GSWIP_PCE_GCTRL_0_MTFL);
8878206e0ceSHauke Mehrtens 	if (err) {
8888206e0ceSHauke Mehrtens 		dev_err(priv->dev, "MAC flushing didn't finish\n");
8898206e0ceSHauke Mehrtens 		return err;
8908206e0ceSHauke Mehrtens 	}
89114fceff4SHauke Mehrtens 
892c40bb4feSAleksander Jan Bajkowski 	ds->mtu_enforcement_ingress = true;
893c40bb4feSAleksander Jan Bajkowski 
89414fceff4SHauke Mehrtens 	gswip_port_enable(ds, cpu_port, NULL);
8950ee2af4eSVladimir Oltean 
8960ee2af4eSVladimir Oltean 	ds->configure_vlan_while_not_filtering = false;
8970ee2af4eSVladimir Oltean 
89814fceff4SHauke Mehrtens 	return 0;
89914fceff4SHauke Mehrtens }
90014fceff4SHauke Mehrtens 
gswip_get_tag_protocol(struct dsa_switch * ds,int port,enum dsa_tag_protocol mp)90114fceff4SHauke Mehrtens static enum dsa_tag_protocol gswip_get_tag_protocol(struct dsa_switch *ds,
9024d776482SFlorian Fainelli 						    int port,
9034d776482SFlorian Fainelli 						    enum dsa_tag_protocol mp)
90414fceff4SHauke Mehrtens {
90514fceff4SHauke Mehrtens 	return DSA_TAG_PROTO_GSWIP;
90614fceff4SHauke Mehrtens }
90714fceff4SHauke Mehrtens 
gswip_vlan_active_create(struct gswip_priv * priv,struct net_device * bridge,int fid,u16 vid)9088206e0ceSHauke Mehrtens static int gswip_vlan_active_create(struct gswip_priv *priv,
9098206e0ceSHauke Mehrtens 				    struct net_device *bridge,
9108206e0ceSHauke Mehrtens 				    int fid, u16 vid)
9118206e0ceSHauke Mehrtens {
9128206e0ceSHauke Mehrtens 	struct gswip_pce_table_entry vlan_active = {0,};
9138206e0ceSHauke Mehrtens 	unsigned int max_ports = priv->hw_info->max_ports;
9148206e0ceSHauke Mehrtens 	int idx = -1;
9158206e0ceSHauke Mehrtens 	int err;
9168206e0ceSHauke Mehrtens 	int i;
9178206e0ceSHauke Mehrtens 
9188206e0ceSHauke Mehrtens 	/* Look for a free slot */
9198206e0ceSHauke Mehrtens 	for (i = max_ports; i < ARRAY_SIZE(priv->vlans); i++) {
9208206e0ceSHauke Mehrtens 		if (!priv->vlans[i].bridge) {
9218206e0ceSHauke Mehrtens 			idx = i;
9228206e0ceSHauke Mehrtens 			break;
9238206e0ceSHauke Mehrtens 		}
9248206e0ceSHauke Mehrtens 	}
9258206e0ceSHauke Mehrtens 
9268206e0ceSHauke Mehrtens 	if (idx == -1)
9278206e0ceSHauke Mehrtens 		return -ENOSPC;
9288206e0ceSHauke Mehrtens 
9298206e0ceSHauke Mehrtens 	if (fid == -1)
9308206e0ceSHauke Mehrtens 		fid = idx;
9318206e0ceSHauke Mehrtens 
9328206e0ceSHauke Mehrtens 	vlan_active.index = idx;
9338206e0ceSHauke Mehrtens 	vlan_active.table = GSWIP_TABLE_ACTIVE_VLAN;
9348206e0ceSHauke Mehrtens 	vlan_active.key[0] = vid;
9358206e0ceSHauke Mehrtens 	vlan_active.val[0] = fid;
9368206e0ceSHauke Mehrtens 	vlan_active.valid = true;
9378206e0ceSHauke Mehrtens 
9388206e0ceSHauke Mehrtens 	err = gswip_pce_table_entry_write(priv, &vlan_active);
9398206e0ceSHauke Mehrtens 	if (err) {
9408206e0ceSHauke Mehrtens 		dev_err(priv->dev, "failed to write active VLAN: %d\n",	err);
9418206e0ceSHauke Mehrtens 		return err;
9428206e0ceSHauke Mehrtens 	}
9438206e0ceSHauke Mehrtens 
9448206e0ceSHauke Mehrtens 	priv->vlans[idx].bridge = bridge;
9458206e0ceSHauke Mehrtens 	priv->vlans[idx].vid = vid;
9468206e0ceSHauke Mehrtens 	priv->vlans[idx].fid = fid;
9478206e0ceSHauke Mehrtens 
9488206e0ceSHauke Mehrtens 	return idx;
9498206e0ceSHauke Mehrtens }
9508206e0ceSHauke Mehrtens 
gswip_vlan_active_remove(struct gswip_priv * priv,int idx)9518206e0ceSHauke Mehrtens static int gswip_vlan_active_remove(struct gswip_priv *priv, int idx)
9528206e0ceSHauke Mehrtens {
9538206e0ceSHauke Mehrtens 	struct gswip_pce_table_entry vlan_active = {0,};
9548206e0ceSHauke Mehrtens 	int err;
9558206e0ceSHauke Mehrtens 
9568206e0ceSHauke Mehrtens 	vlan_active.index = idx;
9578206e0ceSHauke Mehrtens 	vlan_active.table = GSWIP_TABLE_ACTIVE_VLAN;
9588206e0ceSHauke Mehrtens 	vlan_active.valid = false;
9598206e0ceSHauke Mehrtens 	err = gswip_pce_table_entry_write(priv, &vlan_active);
9608206e0ceSHauke Mehrtens 	if (err)
9618206e0ceSHauke Mehrtens 		dev_err(priv->dev, "failed to delete active VLAN: %d\n", err);
9628206e0ceSHauke Mehrtens 	priv->vlans[idx].bridge = NULL;
9638206e0ceSHauke Mehrtens 
9648206e0ceSHauke Mehrtens 	return err;
9658206e0ceSHauke Mehrtens }
9668206e0ceSHauke Mehrtens 
gswip_vlan_add_unaware(struct gswip_priv * priv,struct net_device * bridge,int port)9678206e0ceSHauke Mehrtens static int gswip_vlan_add_unaware(struct gswip_priv *priv,
9688206e0ceSHauke Mehrtens 				  struct net_device *bridge, int port)
9698206e0ceSHauke Mehrtens {
9708206e0ceSHauke Mehrtens 	struct gswip_pce_table_entry vlan_mapping = {0,};
9718206e0ceSHauke Mehrtens 	unsigned int max_ports = priv->hw_info->max_ports;
9728206e0ceSHauke Mehrtens 	unsigned int cpu_port = priv->hw_info->cpu_port;
9738206e0ceSHauke Mehrtens 	bool active_vlan_created = false;
9748206e0ceSHauke Mehrtens 	int idx = -1;
9758206e0ceSHauke Mehrtens 	int i;
9768206e0ceSHauke Mehrtens 	int err;
9778206e0ceSHauke Mehrtens 
9788206e0ceSHauke Mehrtens 	/* Check if there is already a page for this bridge */
9798206e0ceSHauke Mehrtens 	for (i = max_ports; i < ARRAY_SIZE(priv->vlans); i++) {
9808206e0ceSHauke Mehrtens 		if (priv->vlans[i].bridge == bridge) {
9818206e0ceSHauke Mehrtens 			idx = i;
9828206e0ceSHauke Mehrtens 			break;
9838206e0ceSHauke Mehrtens 		}
9848206e0ceSHauke Mehrtens 	}
9858206e0ceSHauke Mehrtens 
9868206e0ceSHauke Mehrtens 	/* If this bridge is not programmed yet, add a Active VLAN table
9878206e0ceSHauke Mehrtens 	 * entry in a free slot and prepare the VLAN mapping table entry.
9888206e0ceSHauke Mehrtens 	 */
9898206e0ceSHauke Mehrtens 	if (idx == -1) {
9908206e0ceSHauke Mehrtens 		idx = gswip_vlan_active_create(priv, bridge, -1, 0);
9918206e0ceSHauke Mehrtens 		if (idx < 0)
9928206e0ceSHauke Mehrtens 			return idx;
9938206e0ceSHauke Mehrtens 		active_vlan_created = true;
9948206e0ceSHauke Mehrtens 
9958206e0ceSHauke Mehrtens 		vlan_mapping.index = idx;
9968206e0ceSHauke Mehrtens 		vlan_mapping.table = GSWIP_TABLE_VLAN_MAPPING;
9978206e0ceSHauke Mehrtens 		/* VLAN ID byte, maps to the VLAN ID of vlan active table */
9988206e0ceSHauke Mehrtens 		vlan_mapping.val[0] = 0;
9998206e0ceSHauke Mehrtens 	} else {
10008206e0ceSHauke Mehrtens 		/* Read the existing VLAN mapping entry from the switch */
10018206e0ceSHauke Mehrtens 		vlan_mapping.index = idx;
10028206e0ceSHauke Mehrtens 		vlan_mapping.table = GSWIP_TABLE_VLAN_MAPPING;
10038206e0ceSHauke Mehrtens 		err = gswip_pce_table_entry_read(priv, &vlan_mapping);
10048206e0ceSHauke Mehrtens 		if (err) {
10058206e0ceSHauke Mehrtens 			dev_err(priv->dev, "failed to read VLAN mapping: %d\n",
10068206e0ceSHauke Mehrtens 				err);
10078206e0ceSHauke Mehrtens 			return err;
10088206e0ceSHauke Mehrtens 		}
10098206e0ceSHauke Mehrtens 	}
10108206e0ceSHauke Mehrtens 
10118206e0ceSHauke Mehrtens 	/* Update the VLAN mapping entry and write it to the switch */
10128206e0ceSHauke Mehrtens 	vlan_mapping.val[1] |= BIT(cpu_port);
10138206e0ceSHauke Mehrtens 	vlan_mapping.val[1] |= BIT(port);
10148206e0ceSHauke Mehrtens 	err = gswip_pce_table_entry_write(priv, &vlan_mapping);
10158206e0ceSHauke Mehrtens 	if (err) {
10168206e0ceSHauke Mehrtens 		dev_err(priv->dev, "failed to write VLAN mapping: %d\n", err);
10178206e0ceSHauke Mehrtens 		/* In case an Active VLAN was creaetd delete it again */
10188206e0ceSHauke Mehrtens 		if (active_vlan_created)
10198206e0ceSHauke Mehrtens 			gswip_vlan_active_remove(priv, idx);
10208206e0ceSHauke Mehrtens 		return err;
10218206e0ceSHauke Mehrtens 	}
10228206e0ceSHauke Mehrtens 
10238206e0ceSHauke Mehrtens 	gswip_switch_w(priv, 0, GSWIP_PCE_DEFPVID(port));
10248206e0ceSHauke Mehrtens 	return 0;
10258206e0ceSHauke Mehrtens }
10268206e0ceSHauke Mehrtens 
gswip_vlan_add_aware(struct gswip_priv * priv,struct net_device * bridge,int port,u16 vid,bool untagged,bool pvid)10279bbb1c05SHauke Mehrtens static int gswip_vlan_add_aware(struct gswip_priv *priv,
10289bbb1c05SHauke Mehrtens 				struct net_device *bridge, int port,
10299bbb1c05SHauke Mehrtens 				u16 vid, bool untagged,
10309bbb1c05SHauke Mehrtens 				bool pvid)
10319bbb1c05SHauke Mehrtens {
10329bbb1c05SHauke Mehrtens 	struct gswip_pce_table_entry vlan_mapping = {0,};
10339bbb1c05SHauke Mehrtens 	unsigned int max_ports = priv->hw_info->max_ports;
10349bbb1c05SHauke Mehrtens 	unsigned int cpu_port = priv->hw_info->cpu_port;
10359bbb1c05SHauke Mehrtens 	bool active_vlan_created = false;
10369bbb1c05SHauke Mehrtens 	int idx = -1;
10379bbb1c05SHauke Mehrtens 	int fid = -1;
10389bbb1c05SHauke Mehrtens 	int i;
10399bbb1c05SHauke Mehrtens 	int err;
10409bbb1c05SHauke Mehrtens 
10419bbb1c05SHauke Mehrtens 	/* Check if there is already a page for this bridge */
10429bbb1c05SHauke Mehrtens 	for (i = max_ports; i < ARRAY_SIZE(priv->vlans); i++) {
10439bbb1c05SHauke Mehrtens 		if (priv->vlans[i].bridge == bridge) {
10449bbb1c05SHauke Mehrtens 			if (fid != -1 && fid != priv->vlans[i].fid)
10459bbb1c05SHauke Mehrtens 				dev_err(priv->dev, "one bridge with multiple flow ids\n");
10469bbb1c05SHauke Mehrtens 			fid = priv->vlans[i].fid;
10479bbb1c05SHauke Mehrtens 			if (priv->vlans[i].vid == vid) {
10489bbb1c05SHauke Mehrtens 				idx = i;
10499bbb1c05SHauke Mehrtens 				break;
10509bbb1c05SHauke Mehrtens 			}
10519bbb1c05SHauke Mehrtens 		}
10529bbb1c05SHauke Mehrtens 	}
10539bbb1c05SHauke Mehrtens 
10549bbb1c05SHauke Mehrtens 	/* If this bridge is not programmed yet, add a Active VLAN table
10559bbb1c05SHauke Mehrtens 	 * entry in a free slot and prepare the VLAN mapping table entry.
10569bbb1c05SHauke Mehrtens 	 */
10579bbb1c05SHauke Mehrtens 	if (idx == -1) {
10589bbb1c05SHauke Mehrtens 		idx = gswip_vlan_active_create(priv, bridge, fid, vid);
10599bbb1c05SHauke Mehrtens 		if (idx < 0)
10609bbb1c05SHauke Mehrtens 			return idx;
10619bbb1c05SHauke Mehrtens 		active_vlan_created = true;
10629bbb1c05SHauke Mehrtens 
10639bbb1c05SHauke Mehrtens 		vlan_mapping.index = idx;
10649bbb1c05SHauke Mehrtens 		vlan_mapping.table = GSWIP_TABLE_VLAN_MAPPING;
10659bbb1c05SHauke Mehrtens 		/* VLAN ID byte, maps to the VLAN ID of vlan active table */
10669bbb1c05SHauke Mehrtens 		vlan_mapping.val[0] = vid;
10679bbb1c05SHauke Mehrtens 	} else {
10689bbb1c05SHauke Mehrtens 		/* Read the existing VLAN mapping entry from the switch */
10699bbb1c05SHauke Mehrtens 		vlan_mapping.index = idx;
10709bbb1c05SHauke Mehrtens 		vlan_mapping.table = GSWIP_TABLE_VLAN_MAPPING;
10719bbb1c05SHauke Mehrtens 		err = gswip_pce_table_entry_read(priv, &vlan_mapping);
10729bbb1c05SHauke Mehrtens 		if (err) {
10739bbb1c05SHauke Mehrtens 			dev_err(priv->dev, "failed to read VLAN mapping: %d\n",
10749bbb1c05SHauke Mehrtens 				err);
10759bbb1c05SHauke Mehrtens 			return err;
10769bbb1c05SHauke Mehrtens 		}
10779bbb1c05SHauke Mehrtens 	}
10789bbb1c05SHauke Mehrtens 
10799bbb1c05SHauke Mehrtens 	vlan_mapping.val[0] = vid;
10809bbb1c05SHauke Mehrtens 	/* Update the VLAN mapping entry and write it to the switch */
10819bbb1c05SHauke Mehrtens 	vlan_mapping.val[1] |= BIT(cpu_port);
10829bbb1c05SHauke Mehrtens 	vlan_mapping.val[2] |= BIT(cpu_port);
10839bbb1c05SHauke Mehrtens 	vlan_mapping.val[1] |= BIT(port);
10849bbb1c05SHauke Mehrtens 	if (untagged)
10859bbb1c05SHauke Mehrtens 		vlan_mapping.val[2] &= ~BIT(port);
10869bbb1c05SHauke Mehrtens 	else
10879bbb1c05SHauke Mehrtens 		vlan_mapping.val[2] |= BIT(port);
10889bbb1c05SHauke Mehrtens 	err = gswip_pce_table_entry_write(priv, &vlan_mapping);
10899bbb1c05SHauke Mehrtens 	if (err) {
10909bbb1c05SHauke Mehrtens 		dev_err(priv->dev, "failed to write VLAN mapping: %d\n", err);
10919bbb1c05SHauke Mehrtens 		/* In case an Active VLAN was creaetd delete it again */
10929bbb1c05SHauke Mehrtens 		if (active_vlan_created)
10939bbb1c05SHauke Mehrtens 			gswip_vlan_active_remove(priv, idx);
10949bbb1c05SHauke Mehrtens 		return err;
10959bbb1c05SHauke Mehrtens 	}
10969bbb1c05SHauke Mehrtens 
10979bbb1c05SHauke Mehrtens 	if (pvid)
10989bbb1c05SHauke Mehrtens 		gswip_switch_w(priv, idx, GSWIP_PCE_DEFPVID(port));
10999bbb1c05SHauke Mehrtens 
11009bbb1c05SHauke Mehrtens 	return 0;
11019bbb1c05SHauke Mehrtens }
11029bbb1c05SHauke Mehrtens 
gswip_vlan_remove(struct gswip_priv * priv,struct net_device * bridge,int port,u16 vid,bool pvid,bool vlan_aware)11038206e0ceSHauke Mehrtens static int gswip_vlan_remove(struct gswip_priv *priv,
11048206e0ceSHauke Mehrtens 			     struct net_device *bridge, int port,
11058206e0ceSHauke Mehrtens 			     u16 vid, bool pvid, bool vlan_aware)
11068206e0ceSHauke Mehrtens {
11078206e0ceSHauke Mehrtens 	struct gswip_pce_table_entry vlan_mapping = {0,};
11088206e0ceSHauke Mehrtens 	unsigned int max_ports = priv->hw_info->max_ports;
11098206e0ceSHauke Mehrtens 	unsigned int cpu_port = priv->hw_info->cpu_port;
11108206e0ceSHauke Mehrtens 	int idx = -1;
11118206e0ceSHauke Mehrtens 	int i;
11128206e0ceSHauke Mehrtens 	int err;
11138206e0ceSHauke Mehrtens 
11148206e0ceSHauke Mehrtens 	/* Check if there is already a page for this bridge */
11158206e0ceSHauke Mehrtens 	for (i = max_ports; i < ARRAY_SIZE(priv->vlans); i++) {
11168206e0ceSHauke Mehrtens 		if (priv->vlans[i].bridge == bridge &&
11178206e0ceSHauke Mehrtens 		    (!vlan_aware || priv->vlans[i].vid == vid)) {
11188206e0ceSHauke Mehrtens 			idx = i;
11198206e0ceSHauke Mehrtens 			break;
11208206e0ceSHauke Mehrtens 		}
11218206e0ceSHauke Mehrtens 	}
11228206e0ceSHauke Mehrtens 
11238206e0ceSHauke Mehrtens 	if (idx == -1) {
11248206e0ceSHauke Mehrtens 		dev_err(priv->dev, "bridge to leave does not exists\n");
11258206e0ceSHauke Mehrtens 		return -ENOENT;
11268206e0ceSHauke Mehrtens 	}
11278206e0ceSHauke Mehrtens 
11288206e0ceSHauke Mehrtens 	vlan_mapping.index = idx;
11298206e0ceSHauke Mehrtens 	vlan_mapping.table = GSWIP_TABLE_VLAN_MAPPING;
11308206e0ceSHauke Mehrtens 	err = gswip_pce_table_entry_read(priv, &vlan_mapping);
11318206e0ceSHauke Mehrtens 	if (err) {
11328206e0ceSHauke Mehrtens 		dev_err(priv->dev, "failed to read VLAN mapping: %d\n",	err);
11338206e0ceSHauke Mehrtens 		return err;
11348206e0ceSHauke Mehrtens 	}
11358206e0ceSHauke Mehrtens 
11368206e0ceSHauke Mehrtens 	vlan_mapping.val[1] &= ~BIT(port);
11378206e0ceSHauke Mehrtens 	vlan_mapping.val[2] &= ~BIT(port);
11388206e0ceSHauke Mehrtens 	err = gswip_pce_table_entry_write(priv, &vlan_mapping);
11398206e0ceSHauke Mehrtens 	if (err) {
11408206e0ceSHauke Mehrtens 		dev_err(priv->dev, "failed to write VLAN mapping: %d\n", err);
11418206e0ceSHauke Mehrtens 		return err;
11428206e0ceSHauke Mehrtens 	}
11438206e0ceSHauke Mehrtens 
11448206e0ceSHauke Mehrtens 	/* In case all ports are removed from the bridge, remove the VLAN */
11458206e0ceSHauke Mehrtens 	if ((vlan_mapping.val[1] & ~BIT(cpu_port)) == 0) {
11468206e0ceSHauke Mehrtens 		err = gswip_vlan_active_remove(priv, idx);
11478206e0ceSHauke Mehrtens 		if (err) {
11488206e0ceSHauke Mehrtens 			dev_err(priv->dev, "failed to write active VLAN: %d\n",
11498206e0ceSHauke Mehrtens 				err);
11508206e0ceSHauke Mehrtens 			return err;
11518206e0ceSHauke Mehrtens 		}
11528206e0ceSHauke Mehrtens 	}
11538206e0ceSHauke Mehrtens 
11548206e0ceSHauke Mehrtens 	/* GSWIP 2.2 (GRX300) and later program here the VID directly. */
11558206e0ceSHauke Mehrtens 	if (pvid)
11568206e0ceSHauke Mehrtens 		gswip_switch_w(priv, 0, GSWIP_PCE_DEFPVID(port));
11578206e0ceSHauke Mehrtens 
11588206e0ceSHauke Mehrtens 	return 0;
11598206e0ceSHauke Mehrtens }
11608206e0ceSHauke Mehrtens 
gswip_port_bridge_join(struct dsa_switch * ds,int port,struct dsa_bridge bridge,bool * tx_fwd_offload,struct netlink_ext_ack * extack)11618206e0ceSHauke Mehrtens static int gswip_port_bridge_join(struct dsa_switch *ds, int port,
1162b079922bSVladimir Oltean 				  struct dsa_bridge bridge,
116306b9cce4SVladimir Oltean 				  bool *tx_fwd_offload,
116406b9cce4SVladimir Oltean 				  struct netlink_ext_ack *extack)
11658206e0ceSHauke Mehrtens {
1166d3eed0e5SVladimir Oltean 	struct net_device *br = bridge.dev;
11678206e0ceSHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
11688206e0ceSHauke Mehrtens 	int err;
11698206e0ceSHauke Mehrtens 
11709bbb1c05SHauke Mehrtens 	/* When the bridge uses VLAN filtering we have to configure VLAN
11719bbb1c05SHauke Mehrtens 	 * specific bridges. No bridge is configured here.
11729bbb1c05SHauke Mehrtens 	 */
1173d3eed0e5SVladimir Oltean 	if (!br_vlan_enabled(br)) {
1174d3eed0e5SVladimir Oltean 		err = gswip_vlan_add_unaware(priv, br, port);
11758206e0ceSHauke Mehrtens 		if (err)
11768206e0ceSHauke Mehrtens 			return err;
11779bbb1c05SHauke Mehrtens 		priv->port_vlan_filter &= ~BIT(port);
11789bbb1c05SHauke Mehrtens 	} else {
11799bbb1c05SHauke Mehrtens 		priv->port_vlan_filter |= BIT(port);
11809bbb1c05SHauke Mehrtens 	}
11818206e0ceSHauke Mehrtens 	return gswip_add_single_port_br(priv, port, false);
11828206e0ceSHauke Mehrtens }
11838206e0ceSHauke Mehrtens 
gswip_port_bridge_leave(struct dsa_switch * ds,int port,struct dsa_bridge bridge)11848206e0ceSHauke Mehrtens static void gswip_port_bridge_leave(struct dsa_switch *ds, int port,
1185d3eed0e5SVladimir Oltean 				    struct dsa_bridge bridge)
11868206e0ceSHauke Mehrtens {
1187d3eed0e5SVladimir Oltean 	struct net_device *br = bridge.dev;
11888206e0ceSHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
11898206e0ceSHauke Mehrtens 
11908206e0ceSHauke Mehrtens 	gswip_add_single_port_br(priv, port, true);
11918206e0ceSHauke Mehrtens 
11929bbb1c05SHauke Mehrtens 	/* When the bridge uses VLAN filtering we have to configure VLAN
11939bbb1c05SHauke Mehrtens 	 * specific bridges. No bridge is configured here.
11949bbb1c05SHauke Mehrtens 	 */
1195d3eed0e5SVladimir Oltean 	if (!br_vlan_enabled(br))
1196d3eed0e5SVladimir Oltean 		gswip_vlan_remove(priv, br, port, 0, true, false);
11978206e0ceSHauke Mehrtens }
11988206e0ceSHauke Mehrtens 
gswip_port_vlan_prepare(struct dsa_switch * ds,int port,const struct switchdev_obj_port_vlan * vlan,struct netlink_ext_ack * extack)11999bbb1c05SHauke Mehrtens static int gswip_port_vlan_prepare(struct dsa_switch *ds, int port,
120031046a5fSVladimir Oltean 				   const struct switchdev_obj_port_vlan *vlan,
120131046a5fSVladimir Oltean 				   struct netlink_ext_ack *extack)
12029bbb1c05SHauke Mehrtens {
120341fb0cf1SVladimir Oltean 	struct net_device *bridge = dsa_port_bridge_dev_get(dsa_to_port(ds, port));
12049bbb1c05SHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
12059bbb1c05SHauke Mehrtens 	unsigned int max_ports = priv->hw_info->max_ports;
12069bbb1c05SHauke Mehrtens 	int pos = max_ports;
1207b7a9e0daSVladimir Oltean 	int i, idx = -1;
12089bbb1c05SHauke Mehrtens 
12099bbb1c05SHauke Mehrtens 	/* We only support VLAN filtering on bridges */
12109bbb1c05SHauke Mehrtens 	if (!dsa_is_cpu_port(ds, port) && !bridge)
12119bbb1c05SHauke Mehrtens 		return -EOPNOTSUPP;
12129bbb1c05SHauke Mehrtens 
12139bbb1c05SHauke Mehrtens 	/* Check if there is already a page for this VLAN */
12149bbb1c05SHauke Mehrtens 	for (i = max_ports; i < ARRAY_SIZE(priv->vlans); i++) {
12159bbb1c05SHauke Mehrtens 		if (priv->vlans[i].bridge == bridge &&
1216b7a9e0daSVladimir Oltean 		    priv->vlans[i].vid == vlan->vid) {
12179bbb1c05SHauke Mehrtens 			idx = i;
12189bbb1c05SHauke Mehrtens 			break;
12199bbb1c05SHauke Mehrtens 		}
12209bbb1c05SHauke Mehrtens 	}
12219bbb1c05SHauke Mehrtens 
12229bbb1c05SHauke Mehrtens 	/* If this VLAN is not programmed yet, we have to reserve
12239bbb1c05SHauke Mehrtens 	 * one entry in the VLAN table. Make sure we start at the
12249bbb1c05SHauke Mehrtens 	 * next position round.
12259bbb1c05SHauke Mehrtens 	 */
12269bbb1c05SHauke Mehrtens 	if (idx == -1) {
12279bbb1c05SHauke Mehrtens 		/* Look for a free slot */
12289bbb1c05SHauke Mehrtens 		for (; pos < ARRAY_SIZE(priv->vlans); pos++) {
12299bbb1c05SHauke Mehrtens 			if (!priv->vlans[pos].bridge) {
12309bbb1c05SHauke Mehrtens 				idx = pos;
12319bbb1c05SHauke Mehrtens 				pos++;
12329bbb1c05SHauke Mehrtens 				break;
12339bbb1c05SHauke Mehrtens 			}
12349bbb1c05SHauke Mehrtens 		}
12359bbb1c05SHauke Mehrtens 
123631046a5fSVladimir Oltean 		if (idx == -1) {
123731046a5fSVladimir Oltean 			NL_SET_ERR_MSG_MOD(extack, "No slot in VLAN table");
12389bbb1c05SHauke Mehrtens 			return -ENOSPC;
12399bbb1c05SHauke Mehrtens 		}
124031046a5fSVladimir Oltean 	}
12419bbb1c05SHauke Mehrtens 
12429bbb1c05SHauke Mehrtens 	return 0;
12439bbb1c05SHauke Mehrtens }
12449bbb1c05SHauke Mehrtens 
gswip_port_vlan_add(struct dsa_switch * ds,int port,const struct switchdev_obj_port_vlan * vlan,struct netlink_ext_ack * extack)12451958d581SVladimir Oltean static int gswip_port_vlan_add(struct dsa_switch *ds, int port,
124631046a5fSVladimir Oltean 			       const struct switchdev_obj_port_vlan *vlan,
124731046a5fSVladimir Oltean 			       struct netlink_ext_ack *extack)
12489bbb1c05SHauke Mehrtens {
124941fb0cf1SVladimir Oltean 	struct net_device *bridge = dsa_port_bridge_dev_get(dsa_to_port(ds, port));
12509bbb1c05SHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
12519bbb1c05SHauke Mehrtens 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
12529bbb1c05SHauke Mehrtens 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
12531958d581SVladimir Oltean 	int err;
12541958d581SVladimir Oltean 
125531046a5fSVladimir Oltean 	err = gswip_port_vlan_prepare(ds, port, vlan, extack);
12561958d581SVladimir Oltean 	if (err)
12571958d581SVladimir Oltean 		return err;
12589bbb1c05SHauke Mehrtens 
12599bbb1c05SHauke Mehrtens 	/* We have to receive all packets on the CPU port and should not
12609bbb1c05SHauke Mehrtens 	 * do any VLAN filtering here. This is also called with bridge
12619bbb1c05SHauke Mehrtens 	 * NULL and then we do not know for which bridge to configure
12629bbb1c05SHauke Mehrtens 	 * this.
12639bbb1c05SHauke Mehrtens 	 */
12649bbb1c05SHauke Mehrtens 	if (dsa_is_cpu_port(ds, port))
12651958d581SVladimir Oltean 		return 0;
12669bbb1c05SHauke Mehrtens 
12671958d581SVladimir Oltean 	return gswip_vlan_add_aware(priv, bridge, port, vlan->vid,
12681958d581SVladimir Oltean 				    untagged, pvid);
12699bbb1c05SHauke Mehrtens }
12709bbb1c05SHauke Mehrtens 
gswip_port_vlan_del(struct dsa_switch * ds,int port,const struct switchdev_obj_port_vlan * vlan)12719bbb1c05SHauke Mehrtens static int gswip_port_vlan_del(struct dsa_switch *ds, int port,
12729bbb1c05SHauke Mehrtens 			       const struct switchdev_obj_port_vlan *vlan)
12739bbb1c05SHauke Mehrtens {
127441fb0cf1SVladimir Oltean 	struct net_device *bridge = dsa_port_bridge_dev_get(dsa_to_port(ds, port));
12759bbb1c05SHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
12769bbb1c05SHauke Mehrtens 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
12779bbb1c05SHauke Mehrtens 
12789bbb1c05SHauke Mehrtens 	/* We have to receive all packets on the CPU port and should not
12799bbb1c05SHauke Mehrtens 	 * do any VLAN filtering here. This is also called with bridge
12809bbb1c05SHauke Mehrtens 	 * NULL and then we do not know for which bridge to configure
12819bbb1c05SHauke Mehrtens 	 * this.
12829bbb1c05SHauke Mehrtens 	 */
12839bbb1c05SHauke Mehrtens 	if (dsa_is_cpu_port(ds, port))
12849bbb1c05SHauke Mehrtens 		return 0;
12859bbb1c05SHauke Mehrtens 
1286b7a9e0daSVladimir Oltean 	return gswip_vlan_remove(priv, bridge, port, vlan->vid, pvid, true);
12879bbb1c05SHauke Mehrtens }
12889bbb1c05SHauke Mehrtens 
gswip_port_fast_age(struct dsa_switch * ds,int port)128945813481SHauke Mehrtens static void gswip_port_fast_age(struct dsa_switch *ds, int port)
129045813481SHauke Mehrtens {
129145813481SHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
129245813481SHauke Mehrtens 	struct gswip_pce_table_entry mac_bridge = {0,};
129345813481SHauke Mehrtens 	int i;
129445813481SHauke Mehrtens 	int err;
129545813481SHauke Mehrtens 
129645813481SHauke Mehrtens 	for (i = 0; i < 2048; i++) {
129745813481SHauke Mehrtens 		mac_bridge.table = GSWIP_TABLE_MAC_BRIDGE;
129845813481SHauke Mehrtens 		mac_bridge.index = i;
129945813481SHauke Mehrtens 
130045813481SHauke Mehrtens 		err = gswip_pce_table_entry_read(priv, &mac_bridge);
130145813481SHauke Mehrtens 		if (err) {
1302d6759172SColin Ian King 			dev_err(priv->dev, "failed to read mac bridge: %d\n",
130345813481SHauke Mehrtens 				err);
130445813481SHauke Mehrtens 			return;
130545813481SHauke Mehrtens 		}
130645813481SHauke Mehrtens 
130745813481SHauke Mehrtens 		if (!mac_bridge.valid)
130845813481SHauke Mehrtens 			continue;
130945813481SHauke Mehrtens 
131045813481SHauke Mehrtens 		if (mac_bridge.val[1] & GSWIP_TABLE_MAC_BRIDGE_STATIC)
131145813481SHauke Mehrtens 			continue;
131245813481SHauke Mehrtens 
131345813481SHauke Mehrtens 		if (((mac_bridge.val[0] & GENMASK(7, 4)) >> 4) != port)
131445813481SHauke Mehrtens 			continue;
131545813481SHauke Mehrtens 
131645813481SHauke Mehrtens 		mac_bridge.valid = false;
131745813481SHauke Mehrtens 		err = gswip_pce_table_entry_write(priv, &mac_bridge);
131845813481SHauke Mehrtens 		if (err) {
1319d6759172SColin Ian King 			dev_err(priv->dev, "failed to write mac bridge: %d\n",
132045813481SHauke Mehrtens 				err);
132145813481SHauke Mehrtens 			return;
132245813481SHauke Mehrtens 		}
132345813481SHauke Mehrtens 	}
132445813481SHauke Mehrtens }
132545813481SHauke Mehrtens 
gswip_port_stp_state_set(struct dsa_switch * ds,int port,u8 state)13268206e0ceSHauke Mehrtens static void gswip_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
13278206e0ceSHauke Mehrtens {
13288206e0ceSHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
13298206e0ceSHauke Mehrtens 	u32 stp_state;
13308206e0ceSHauke Mehrtens 
13318206e0ceSHauke Mehrtens 	switch (state) {
13328206e0ceSHauke Mehrtens 	case BR_STATE_DISABLED:
13338206e0ceSHauke Mehrtens 		gswip_switch_mask(priv, GSWIP_SDMA_PCTRL_EN, 0,
13348206e0ceSHauke Mehrtens 				  GSWIP_SDMA_PCTRLp(port));
13358206e0ceSHauke Mehrtens 		return;
13368206e0ceSHauke Mehrtens 	case BR_STATE_BLOCKING:
13378206e0ceSHauke Mehrtens 	case BR_STATE_LISTENING:
13388206e0ceSHauke Mehrtens 		stp_state = GSWIP_PCE_PCTRL_0_PSTATE_LISTEN;
13398206e0ceSHauke Mehrtens 		break;
13408206e0ceSHauke Mehrtens 	case BR_STATE_LEARNING:
13418206e0ceSHauke Mehrtens 		stp_state = GSWIP_PCE_PCTRL_0_PSTATE_LEARNING;
13428206e0ceSHauke Mehrtens 		break;
13438206e0ceSHauke Mehrtens 	case BR_STATE_FORWARDING:
13448206e0ceSHauke Mehrtens 		stp_state = GSWIP_PCE_PCTRL_0_PSTATE_FORWARDING;
13458206e0ceSHauke Mehrtens 		break;
13468206e0ceSHauke Mehrtens 	default:
13478206e0ceSHauke Mehrtens 		dev_err(priv->dev, "invalid STP state: %d\n", state);
13488206e0ceSHauke Mehrtens 		return;
13498206e0ceSHauke Mehrtens 	}
13508206e0ceSHauke Mehrtens 
13518206e0ceSHauke Mehrtens 	gswip_switch_mask(priv, 0, GSWIP_SDMA_PCTRL_EN,
13528206e0ceSHauke Mehrtens 			  GSWIP_SDMA_PCTRLp(port));
13538206e0ceSHauke Mehrtens 	gswip_switch_mask(priv, GSWIP_PCE_PCTRL_0_PSTATE_MASK, stp_state,
13548206e0ceSHauke Mehrtens 			  GSWIP_PCE_PCTRL_0p(port));
13558206e0ceSHauke Mehrtens }
13568206e0ceSHauke Mehrtens 
gswip_port_fdb(struct dsa_switch * ds,int port,const unsigned char * addr,u16 vid,bool add)135758c59ef9SHauke Mehrtens static int gswip_port_fdb(struct dsa_switch *ds, int port,
135858c59ef9SHauke Mehrtens 			  const unsigned char *addr, u16 vid, bool add)
135958c59ef9SHauke Mehrtens {
136041fb0cf1SVladimir Oltean 	struct net_device *bridge = dsa_port_bridge_dev_get(dsa_to_port(ds, port));
136158c59ef9SHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
136258c59ef9SHauke Mehrtens 	struct gswip_pce_table_entry mac_bridge = {0,};
13637b4149bdSMartin Blumenstingl 	unsigned int max_ports = priv->hw_info->max_ports;
136458c59ef9SHauke Mehrtens 	int fid = -1;
136558c59ef9SHauke Mehrtens 	int i;
136658c59ef9SHauke Mehrtens 	int err;
136758c59ef9SHauke Mehrtens 
136858c59ef9SHauke Mehrtens 	if (!bridge)
136958c59ef9SHauke Mehrtens 		return -EINVAL;
137058c59ef9SHauke Mehrtens 
13717b4149bdSMartin Blumenstingl 	for (i = max_ports; i < ARRAY_SIZE(priv->vlans); i++) {
137258c59ef9SHauke Mehrtens 		if (priv->vlans[i].bridge == bridge) {
137358c59ef9SHauke Mehrtens 			fid = priv->vlans[i].fid;
137458c59ef9SHauke Mehrtens 			break;
137558c59ef9SHauke Mehrtens 		}
137658c59ef9SHauke Mehrtens 	}
137758c59ef9SHauke Mehrtens 
137858c59ef9SHauke Mehrtens 	if (fid == -1) {
137958c59ef9SHauke Mehrtens 		dev_err(priv->dev, "Port not part of a bridge\n");
138058c59ef9SHauke Mehrtens 		return -EINVAL;
138158c59ef9SHauke Mehrtens 	}
138258c59ef9SHauke Mehrtens 
138358c59ef9SHauke Mehrtens 	mac_bridge.table = GSWIP_TABLE_MAC_BRIDGE;
138458c59ef9SHauke Mehrtens 	mac_bridge.key_mode = true;
138558c59ef9SHauke Mehrtens 	mac_bridge.key[0] = addr[5] | (addr[4] << 8);
138658c59ef9SHauke Mehrtens 	mac_bridge.key[1] = addr[3] | (addr[2] << 8);
138758c59ef9SHauke Mehrtens 	mac_bridge.key[2] = addr[1] | (addr[0] << 8);
138858c59ef9SHauke Mehrtens 	mac_bridge.key[3] = fid;
138958c59ef9SHauke Mehrtens 	mac_bridge.val[0] = add ? BIT(port) : 0; /* port map */
139058c59ef9SHauke Mehrtens 	mac_bridge.val[1] = GSWIP_TABLE_MAC_BRIDGE_STATIC;
139158c59ef9SHauke Mehrtens 	mac_bridge.valid = add;
139258c59ef9SHauke Mehrtens 
139358c59ef9SHauke Mehrtens 	err = gswip_pce_table_entry_write(priv, &mac_bridge);
139458c59ef9SHauke Mehrtens 	if (err)
1395d6759172SColin Ian King 		dev_err(priv->dev, "failed to write mac bridge: %d\n", err);
139658c59ef9SHauke Mehrtens 
139758c59ef9SHauke Mehrtens 	return err;
139858c59ef9SHauke Mehrtens }
139958c59ef9SHauke Mehrtens 
gswip_port_fdb_add(struct dsa_switch * ds,int port,const unsigned char * addr,u16 vid,struct dsa_db db)140058c59ef9SHauke Mehrtens static int gswip_port_fdb_add(struct dsa_switch *ds, int port,
1401c2693363SVladimir Oltean 			      const unsigned char *addr, u16 vid,
1402c2693363SVladimir Oltean 			      struct dsa_db db)
140358c59ef9SHauke Mehrtens {
140458c59ef9SHauke Mehrtens 	return gswip_port_fdb(ds, port, addr, vid, true);
140558c59ef9SHauke Mehrtens }
140658c59ef9SHauke Mehrtens 
gswip_port_fdb_del(struct dsa_switch * ds,int port,const unsigned char * addr,u16 vid,struct dsa_db db)140758c59ef9SHauke Mehrtens static int gswip_port_fdb_del(struct dsa_switch *ds, int port,
1408c2693363SVladimir Oltean 			      const unsigned char *addr, u16 vid,
1409c2693363SVladimir Oltean 			      struct dsa_db db)
141058c59ef9SHauke Mehrtens {
141158c59ef9SHauke Mehrtens 	return gswip_port_fdb(ds, port, addr, vid, false);
141258c59ef9SHauke Mehrtens }
141358c59ef9SHauke Mehrtens 
gswip_port_fdb_dump(struct dsa_switch * ds,int port,dsa_fdb_dump_cb_t * cb,void * data)141458c59ef9SHauke Mehrtens static int gswip_port_fdb_dump(struct dsa_switch *ds, int port,
141558c59ef9SHauke Mehrtens 			       dsa_fdb_dump_cb_t *cb, void *data)
141658c59ef9SHauke Mehrtens {
141758c59ef9SHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
141858c59ef9SHauke Mehrtens 	struct gswip_pce_table_entry mac_bridge = {0,};
141958c59ef9SHauke Mehrtens 	unsigned char addr[6];
142058c59ef9SHauke Mehrtens 	int i;
142158c59ef9SHauke Mehrtens 	int err;
142258c59ef9SHauke Mehrtens 
142358c59ef9SHauke Mehrtens 	for (i = 0; i < 2048; i++) {
142458c59ef9SHauke Mehrtens 		mac_bridge.table = GSWIP_TABLE_MAC_BRIDGE;
142558c59ef9SHauke Mehrtens 		mac_bridge.index = i;
142658c59ef9SHauke Mehrtens 
142758c59ef9SHauke Mehrtens 		err = gswip_pce_table_entry_read(priv, &mac_bridge);
142858c59ef9SHauke Mehrtens 		if (err) {
14294951995dSMartin Blumenstingl 			dev_err(priv->dev,
14304951995dSMartin Blumenstingl 				"failed to read mac bridge entry %d: %d\n",
14314951995dSMartin Blumenstingl 				i, err);
143258c59ef9SHauke Mehrtens 			return err;
143358c59ef9SHauke Mehrtens 		}
143458c59ef9SHauke Mehrtens 
143558c59ef9SHauke Mehrtens 		if (!mac_bridge.valid)
143658c59ef9SHauke Mehrtens 			continue;
143758c59ef9SHauke Mehrtens 
143858c59ef9SHauke Mehrtens 		addr[5] = mac_bridge.key[0] & 0xff;
143958c59ef9SHauke Mehrtens 		addr[4] = (mac_bridge.key[0] >> 8) & 0xff;
144058c59ef9SHauke Mehrtens 		addr[3] = mac_bridge.key[1] & 0xff;
144158c59ef9SHauke Mehrtens 		addr[2] = (mac_bridge.key[1] >> 8) & 0xff;
144258c59ef9SHauke Mehrtens 		addr[1] = mac_bridge.key[2] & 0xff;
144358c59ef9SHauke Mehrtens 		addr[0] = (mac_bridge.key[2] >> 8) & 0xff;
144458c59ef9SHauke Mehrtens 		if (mac_bridge.val[1] & GSWIP_TABLE_MAC_BRIDGE_STATIC) {
1445871a73a1SVladimir Oltean 			if (mac_bridge.val[0] & BIT(port)) {
1446871a73a1SVladimir Oltean 				err = cb(addr, 0, true, data);
1447871a73a1SVladimir Oltean 				if (err)
1448871a73a1SVladimir Oltean 					return err;
1449871a73a1SVladimir Oltean 			}
145058c59ef9SHauke Mehrtens 		} else {
1451871a73a1SVladimir Oltean 			if (((mac_bridge.val[0] & GENMASK(7, 4)) >> 4) == port) {
1452871a73a1SVladimir Oltean 				err = cb(addr, 0, false, data);
1453871a73a1SVladimir Oltean 				if (err)
1454871a73a1SVladimir Oltean 					return err;
1455871a73a1SVladimir Oltean 			}
145658c59ef9SHauke Mehrtens 		}
145758c59ef9SHauke Mehrtens 	}
145858c59ef9SHauke Mehrtens 	return 0;
145958c59ef9SHauke Mehrtens }
146058c59ef9SHauke Mehrtens 
gswip_port_max_mtu(struct dsa_switch * ds,int port)1461c40bb4feSAleksander Jan Bajkowski static int gswip_port_max_mtu(struct dsa_switch *ds, int port)
1462c40bb4feSAleksander Jan Bajkowski {
1463c40bb4feSAleksander Jan Bajkowski 	/* Includes 8 bytes for special header. */
1464c40bb4feSAleksander Jan Bajkowski 	return GSWIP_MAX_PACKET_LENGTH - VLAN_ETH_HLEN - ETH_FCS_LEN;
1465c40bb4feSAleksander Jan Bajkowski }
1466c40bb4feSAleksander Jan Bajkowski 
gswip_port_change_mtu(struct dsa_switch * ds,int port,int new_mtu)1467c40bb4feSAleksander Jan Bajkowski static int gswip_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
1468c40bb4feSAleksander Jan Bajkowski {
1469c40bb4feSAleksander Jan Bajkowski 	struct gswip_priv *priv = ds->priv;
1470c40bb4feSAleksander Jan Bajkowski 	int cpu_port = priv->hw_info->cpu_port;
1471c40bb4feSAleksander Jan Bajkowski 
1472c40bb4feSAleksander Jan Bajkowski 	/* CPU port always has maximum mtu of user ports, so use it to set
1473c40bb4feSAleksander Jan Bajkowski 	 * switch frame size, including 8 byte special header.
1474c40bb4feSAleksander Jan Bajkowski 	 */
1475c40bb4feSAleksander Jan Bajkowski 	if (port == cpu_port) {
1476c40bb4feSAleksander Jan Bajkowski 		new_mtu += 8;
1477c40bb4feSAleksander Jan Bajkowski 		gswip_switch_w(priv, VLAN_ETH_HLEN + new_mtu + ETH_FCS_LEN,
1478c40bb4feSAleksander Jan Bajkowski 			       GSWIP_MAC_FLEN);
1479c40bb4feSAleksander Jan Bajkowski 	}
1480c40bb4feSAleksander Jan Bajkowski 
1481c40bb4feSAleksander Jan Bajkowski 	/* Enable MLEN for ports with non-standard MTUs, including the special
1482c40bb4feSAleksander Jan Bajkowski 	 * header on the CPU port added above.
1483c40bb4feSAleksander Jan Bajkowski 	 */
1484c40bb4feSAleksander Jan Bajkowski 	if (new_mtu != ETH_DATA_LEN)
1485c40bb4feSAleksander Jan Bajkowski 		gswip_switch_mask(priv, 0, GSWIP_MAC_CTRL_2_MLEN,
1486c40bb4feSAleksander Jan Bajkowski 				  GSWIP_MAC_CTRL_2p(port));
1487c40bb4feSAleksander Jan Bajkowski 	else
1488c40bb4feSAleksander Jan Bajkowski 		gswip_switch_mask(priv, GSWIP_MAC_CTRL_2_MLEN, 0,
1489c40bb4feSAleksander Jan Bajkowski 				  GSWIP_MAC_CTRL_2p(port));
1490c40bb4feSAleksander Jan Bajkowski 
1491c40bb4feSAleksander Jan Bajkowski 	return 0;
1492c40bb4feSAleksander Jan Bajkowski }
1493c40bb4feSAleksander Jan Bajkowski 
gswip_xrx200_phylink_get_caps(struct dsa_switch * ds,int port,struct phylink_config * config)1494a2279b08SRussell King (Oracle) static void gswip_xrx200_phylink_get_caps(struct dsa_switch *ds, int port,
1495a2279b08SRussell King (Oracle) 					  struct phylink_config *config)
1496a09d042bSAleksander Jan Bajkowski {
1497a09d042bSAleksander Jan Bajkowski 	switch (port) {
1498a09d042bSAleksander Jan Bajkowski 	case 0:
1499a09d042bSAleksander Jan Bajkowski 	case 1:
1500a2279b08SRussell King (Oracle) 		phy_interface_set_rgmii(config->supported_interfaces);
1501a2279b08SRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_MII,
1502a2279b08SRussell King (Oracle) 			  config->supported_interfaces);
1503a2279b08SRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_REVMII,
1504a2279b08SRussell King (Oracle) 			  config->supported_interfaces);
1505a2279b08SRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_RMII,
1506a2279b08SRussell King (Oracle) 			  config->supported_interfaces);
1507a09d042bSAleksander Jan Bajkowski 		break;
1508a2279b08SRussell King (Oracle) 
1509a09d042bSAleksander Jan Bajkowski 	case 2:
1510a09d042bSAleksander Jan Bajkowski 	case 3:
1511a09d042bSAleksander Jan Bajkowski 	case 4:
1512a2279b08SRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_INTERNAL,
1513a2279b08SRussell King (Oracle) 			  config->supported_interfaces);
1514a09d042bSAleksander Jan Bajkowski 		break;
1515a2279b08SRussell King (Oracle) 
1516a09d042bSAleksander Jan Bajkowski 	case 5:
1517a2279b08SRussell King (Oracle) 		phy_interface_set_rgmii(config->supported_interfaces);
1518a2279b08SRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_INTERNAL,
1519a2279b08SRussell King (Oracle) 			  config->supported_interfaces);
1520a09d042bSAleksander Jan Bajkowski 		break;
1521a09d042bSAleksander Jan Bajkowski 	}
1522a09d042bSAleksander Jan Bajkowski 
1523a2279b08SRussell King (Oracle) 	config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
1524a2279b08SRussell King (Oracle) 		MAC_10 | MAC_100 | MAC_1000;
1525a09d042bSAleksander Jan Bajkowski }
1526a09d042bSAleksander Jan Bajkowski 
gswip_xrx300_phylink_get_caps(struct dsa_switch * ds,int port,struct phylink_config * config)1527a2279b08SRussell King (Oracle) static void gswip_xrx300_phylink_get_caps(struct dsa_switch *ds, int port,
1528a2279b08SRussell King (Oracle) 					  struct phylink_config *config)
1529a09d042bSAleksander Jan Bajkowski {
1530a09d042bSAleksander Jan Bajkowski 	switch (port) {
1531a09d042bSAleksander Jan Bajkowski 	case 0:
1532a2279b08SRussell King (Oracle) 		phy_interface_set_rgmii(config->supported_interfaces);
1533a2279b08SRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_GMII,
1534a2279b08SRussell King (Oracle) 			  config->supported_interfaces);
1535a2279b08SRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_RMII,
1536a2279b08SRussell King (Oracle) 			  config->supported_interfaces);
1537a09d042bSAleksander Jan Bajkowski 		break;
1538a2279b08SRussell King (Oracle) 
1539a09d042bSAleksander Jan Bajkowski 	case 1:
1540a09d042bSAleksander Jan Bajkowski 	case 2:
1541a09d042bSAleksander Jan Bajkowski 	case 3:
1542a09d042bSAleksander Jan Bajkowski 	case 4:
1543a2279b08SRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_INTERNAL,
1544a2279b08SRussell King (Oracle) 			  config->supported_interfaces);
1545a09d042bSAleksander Jan Bajkowski 		break;
1546a2279b08SRussell King (Oracle) 
1547a09d042bSAleksander Jan Bajkowski 	case 5:
1548a2279b08SRussell King (Oracle) 		phy_interface_set_rgmii(config->supported_interfaces);
1549a2279b08SRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_INTERNAL,
1550a2279b08SRussell King (Oracle) 			  config->supported_interfaces);
1551a2279b08SRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_RMII,
1552a2279b08SRussell King (Oracle) 			  config->supported_interfaces);
1553a09d042bSAleksander Jan Bajkowski 		break;
155414fceff4SHauke Mehrtens 	}
155514fceff4SHauke Mehrtens 
1556a2279b08SRussell King (Oracle) 	config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
1557a2279b08SRussell King (Oracle) 		MAC_10 | MAC_100 | MAC_1000;
1558a09d042bSAleksander Jan Bajkowski }
1559a09d042bSAleksander Jan Bajkowski 
gswip_port_set_link(struct gswip_priv * priv,int port,bool link)15603e9005beSMartin Blumenstingl static void gswip_port_set_link(struct gswip_priv *priv, int port, bool link)
15613e9005beSMartin Blumenstingl {
15623e9005beSMartin Blumenstingl 	u32 mdio_phy;
15633e9005beSMartin Blumenstingl 
15643e9005beSMartin Blumenstingl 	if (link)
15653e9005beSMartin Blumenstingl 		mdio_phy = GSWIP_MDIO_PHY_LINK_UP;
15663e9005beSMartin Blumenstingl 	else
15673e9005beSMartin Blumenstingl 		mdio_phy = GSWIP_MDIO_PHY_LINK_DOWN;
15683e9005beSMartin Blumenstingl 
15693e9005beSMartin Blumenstingl 	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_LINK_MASK, mdio_phy,
15703e9005beSMartin Blumenstingl 			GSWIP_MDIO_PHYp(port));
15713e9005beSMartin Blumenstingl }
15723e9005beSMartin Blumenstingl 
gswip_port_set_speed(struct gswip_priv * priv,int port,int speed,phy_interface_t interface)15733e9005beSMartin Blumenstingl static void gswip_port_set_speed(struct gswip_priv *priv, int port, int speed,
15743e9005beSMartin Blumenstingl 				 phy_interface_t interface)
15753e9005beSMartin Blumenstingl {
15763e9005beSMartin Blumenstingl 	u32 mdio_phy = 0, mii_cfg = 0, mac_ctrl_0 = 0;
15773e9005beSMartin Blumenstingl 
15783e9005beSMartin Blumenstingl 	switch (speed) {
15793e9005beSMartin Blumenstingl 	case SPEED_10:
15803e9005beSMartin Blumenstingl 		mdio_phy = GSWIP_MDIO_PHY_SPEED_M10;
15813e9005beSMartin Blumenstingl 
15823e9005beSMartin Blumenstingl 		if (interface == PHY_INTERFACE_MODE_RMII)
15833e9005beSMartin Blumenstingl 			mii_cfg = GSWIP_MII_CFG_RATE_M50;
15843e9005beSMartin Blumenstingl 		else
15853e9005beSMartin Blumenstingl 			mii_cfg = GSWIP_MII_CFG_RATE_M2P5;
15863e9005beSMartin Blumenstingl 
15873e9005beSMartin Blumenstingl 		mac_ctrl_0 = GSWIP_MAC_CTRL_0_GMII_MII;
15883e9005beSMartin Blumenstingl 		break;
15893e9005beSMartin Blumenstingl 
15903e9005beSMartin Blumenstingl 	case SPEED_100:
15913e9005beSMartin Blumenstingl 		mdio_phy = GSWIP_MDIO_PHY_SPEED_M100;
15923e9005beSMartin Blumenstingl 
15933e9005beSMartin Blumenstingl 		if (interface == PHY_INTERFACE_MODE_RMII)
15943e9005beSMartin Blumenstingl 			mii_cfg = GSWIP_MII_CFG_RATE_M50;
15953e9005beSMartin Blumenstingl 		else
15963e9005beSMartin Blumenstingl 			mii_cfg = GSWIP_MII_CFG_RATE_M25;
15973e9005beSMartin Blumenstingl 
15983e9005beSMartin Blumenstingl 		mac_ctrl_0 = GSWIP_MAC_CTRL_0_GMII_MII;
15993e9005beSMartin Blumenstingl 		break;
16003e9005beSMartin Blumenstingl 
16013e9005beSMartin Blumenstingl 	case SPEED_1000:
16023e9005beSMartin Blumenstingl 		mdio_phy = GSWIP_MDIO_PHY_SPEED_G1;
16033e9005beSMartin Blumenstingl 
16043e9005beSMartin Blumenstingl 		mii_cfg = GSWIP_MII_CFG_RATE_M125;
16053e9005beSMartin Blumenstingl 
16063e9005beSMartin Blumenstingl 		mac_ctrl_0 = GSWIP_MAC_CTRL_0_GMII_RGMII;
16073e9005beSMartin Blumenstingl 		break;
16083e9005beSMartin Blumenstingl 	}
16093e9005beSMartin Blumenstingl 
16103e9005beSMartin Blumenstingl 	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_SPEED_MASK, mdio_phy,
16113e9005beSMartin Blumenstingl 			GSWIP_MDIO_PHYp(port));
16123e9005beSMartin Blumenstingl 	gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_RATE_MASK, mii_cfg, port);
16133e9005beSMartin Blumenstingl 	gswip_switch_mask(priv, GSWIP_MAC_CTRL_0_GMII_MASK, mac_ctrl_0,
16143e9005beSMartin Blumenstingl 			  GSWIP_MAC_CTRL_0p(port));
16153e9005beSMartin Blumenstingl }
16163e9005beSMartin Blumenstingl 
gswip_port_set_duplex(struct gswip_priv * priv,int port,int duplex)16173e9005beSMartin Blumenstingl static void gswip_port_set_duplex(struct gswip_priv *priv, int port, int duplex)
16183e9005beSMartin Blumenstingl {
16193e9005beSMartin Blumenstingl 	u32 mac_ctrl_0, mdio_phy;
16203e9005beSMartin Blumenstingl 
16213e9005beSMartin Blumenstingl 	if (duplex == DUPLEX_FULL) {
16223e9005beSMartin Blumenstingl 		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FDUP_EN;
16233e9005beSMartin Blumenstingl 		mdio_phy = GSWIP_MDIO_PHY_FDUP_EN;
16243e9005beSMartin Blumenstingl 	} else {
16253e9005beSMartin Blumenstingl 		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FDUP_DIS;
16263e9005beSMartin Blumenstingl 		mdio_phy = GSWIP_MDIO_PHY_FDUP_DIS;
16273e9005beSMartin Blumenstingl 	}
16283e9005beSMartin Blumenstingl 
16293e9005beSMartin Blumenstingl 	gswip_switch_mask(priv, GSWIP_MAC_CTRL_0_FDUP_MASK, mac_ctrl_0,
16303e9005beSMartin Blumenstingl 			  GSWIP_MAC_CTRL_0p(port));
16313e9005beSMartin Blumenstingl 	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_FDUP_MASK, mdio_phy,
16323e9005beSMartin Blumenstingl 			GSWIP_MDIO_PHYp(port));
16333e9005beSMartin Blumenstingl }
16343e9005beSMartin Blumenstingl 
gswip_port_set_pause(struct gswip_priv * priv,int port,bool tx_pause,bool rx_pause)16353e9005beSMartin Blumenstingl static void gswip_port_set_pause(struct gswip_priv *priv, int port,
16363e9005beSMartin Blumenstingl 				 bool tx_pause, bool rx_pause)
16373e9005beSMartin Blumenstingl {
16383e9005beSMartin Blumenstingl 	u32 mac_ctrl_0, mdio_phy;
16393e9005beSMartin Blumenstingl 
16403e9005beSMartin Blumenstingl 	if (tx_pause && rx_pause) {
16413e9005beSMartin Blumenstingl 		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_RXTX;
16423e9005beSMartin Blumenstingl 		mdio_phy = GSWIP_MDIO_PHY_FCONTX_EN |
16433e9005beSMartin Blumenstingl 			   GSWIP_MDIO_PHY_FCONRX_EN;
16443e9005beSMartin Blumenstingl 	} else if (tx_pause) {
16453e9005beSMartin Blumenstingl 		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_TX;
16463e9005beSMartin Blumenstingl 		mdio_phy = GSWIP_MDIO_PHY_FCONTX_EN |
16473e9005beSMartin Blumenstingl 			   GSWIP_MDIO_PHY_FCONRX_DIS;
16483e9005beSMartin Blumenstingl 	} else if (rx_pause) {
16493e9005beSMartin Blumenstingl 		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_RX;
16503e9005beSMartin Blumenstingl 		mdio_phy = GSWIP_MDIO_PHY_FCONTX_DIS |
16513e9005beSMartin Blumenstingl 			   GSWIP_MDIO_PHY_FCONRX_EN;
16523e9005beSMartin Blumenstingl 	} else {
16533e9005beSMartin Blumenstingl 		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_NONE;
16543e9005beSMartin Blumenstingl 		mdio_phy = GSWIP_MDIO_PHY_FCONTX_DIS |
16553e9005beSMartin Blumenstingl 			   GSWIP_MDIO_PHY_FCONRX_DIS;
16563e9005beSMartin Blumenstingl 	}
16573e9005beSMartin Blumenstingl 
16583e9005beSMartin Blumenstingl 	gswip_switch_mask(priv, GSWIP_MAC_CTRL_0_FCON_MASK,
16593e9005beSMartin Blumenstingl 			  mac_ctrl_0, GSWIP_MAC_CTRL_0p(port));
16603e9005beSMartin Blumenstingl 	gswip_mdio_mask(priv,
16613e9005beSMartin Blumenstingl 			GSWIP_MDIO_PHY_FCONTX_MASK |
16623e9005beSMartin Blumenstingl 			GSWIP_MDIO_PHY_FCONRX_MASK,
16633e9005beSMartin Blumenstingl 			mdio_phy, GSWIP_MDIO_PHYp(port));
16643e9005beSMartin Blumenstingl }
16653e9005beSMartin Blumenstingl 
gswip_phylink_mac_config(struct dsa_switch * ds,int port,unsigned int mode,const struct phylink_link_state * state)166614fceff4SHauke Mehrtens static void gswip_phylink_mac_config(struct dsa_switch *ds, int port,
166714fceff4SHauke Mehrtens 				     unsigned int mode,
166814fceff4SHauke Mehrtens 				     const struct phylink_link_state *state)
166914fceff4SHauke Mehrtens {
167014fceff4SHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
167114fceff4SHauke Mehrtens 	u32 miicfg = 0;
167214fceff4SHauke Mehrtens 
167314fceff4SHauke Mehrtens 	miicfg |= GSWIP_MII_CFG_LDCLKDIS;
167414fceff4SHauke Mehrtens 
167514fceff4SHauke Mehrtens 	switch (state->interface) {
167614fceff4SHauke Mehrtens 	case PHY_INTERFACE_MODE_MII:
167714fceff4SHauke Mehrtens 	case PHY_INTERFACE_MODE_INTERNAL:
167814fceff4SHauke Mehrtens 		miicfg |= GSWIP_MII_CFG_MODE_MIIM;
167914fceff4SHauke Mehrtens 		break;
168014fceff4SHauke Mehrtens 	case PHY_INTERFACE_MODE_REVMII:
168114fceff4SHauke Mehrtens 		miicfg |= GSWIP_MII_CFG_MODE_MIIP;
168214fceff4SHauke Mehrtens 		break;
168314fceff4SHauke Mehrtens 	case PHY_INTERFACE_MODE_RMII:
168414fceff4SHauke Mehrtens 		miicfg |= GSWIP_MII_CFG_MODE_RMIIM;
168514fceff4SHauke Mehrtens 		break;
168614fceff4SHauke Mehrtens 	case PHY_INTERFACE_MODE_RGMII:
168714fceff4SHauke Mehrtens 	case PHY_INTERFACE_MODE_RGMII_ID:
168814fceff4SHauke Mehrtens 	case PHY_INTERFACE_MODE_RGMII_RXID:
168914fceff4SHauke Mehrtens 	case PHY_INTERFACE_MODE_RGMII_TXID:
169014fceff4SHauke Mehrtens 		miicfg |= GSWIP_MII_CFG_MODE_RGMII;
169114fceff4SHauke Mehrtens 		break;
1692a09d042bSAleksander Jan Bajkowski 	case PHY_INTERFACE_MODE_GMII:
1693a09d042bSAleksander Jan Bajkowski 		miicfg |= GSWIP_MII_CFG_MODE_GMII;
1694a09d042bSAleksander Jan Bajkowski 		break;
169514fceff4SHauke Mehrtens 	default:
169614fceff4SHauke Mehrtens 		dev_err(ds->dev,
169714fceff4SHauke Mehrtens 			"Unsupported interface: %d\n", state->interface);
169814fceff4SHauke Mehrtens 		return;
169914fceff4SHauke Mehrtens 	}
17004b592324SMartin Blumenstingl 
17014b592324SMartin Blumenstingl 	gswip_mii_mask_cfg(priv,
17024b592324SMartin Blumenstingl 			   GSWIP_MII_CFG_MODE_MASK | GSWIP_MII_CFG_RMII_CLK |
17034b592324SMartin Blumenstingl 			   GSWIP_MII_CFG_RGMII_IBS | GSWIP_MII_CFG_LDCLKDIS,
17044b592324SMartin Blumenstingl 			   miicfg, port);
170514fceff4SHauke Mehrtens 
170614fceff4SHauke Mehrtens 	switch (state->interface) {
170714fceff4SHauke Mehrtens 	case PHY_INTERFACE_MODE_RGMII_ID:
170814fceff4SHauke Mehrtens 		gswip_mii_mask_pcdu(priv, GSWIP_MII_PCDU_TXDLY_MASK |
170914fceff4SHauke Mehrtens 					  GSWIP_MII_PCDU_RXDLY_MASK, 0, port);
171014fceff4SHauke Mehrtens 		break;
171114fceff4SHauke Mehrtens 	case PHY_INTERFACE_MODE_RGMII_RXID:
171214fceff4SHauke Mehrtens 		gswip_mii_mask_pcdu(priv, GSWIP_MII_PCDU_RXDLY_MASK, 0, port);
171314fceff4SHauke Mehrtens 		break;
171414fceff4SHauke Mehrtens 	case PHY_INTERFACE_MODE_RGMII_TXID:
171514fceff4SHauke Mehrtens 		gswip_mii_mask_pcdu(priv, GSWIP_MII_PCDU_TXDLY_MASK, 0, port);
171614fceff4SHauke Mehrtens 		break;
171714fceff4SHauke Mehrtens 	default:
171814fceff4SHauke Mehrtens 		break;
171914fceff4SHauke Mehrtens 	}
172014fceff4SHauke Mehrtens }
172114fceff4SHauke Mehrtens 
gswip_phylink_mac_link_down(struct dsa_switch * ds,int port,unsigned int mode,phy_interface_t interface)172214fceff4SHauke Mehrtens static void gswip_phylink_mac_link_down(struct dsa_switch *ds, int port,
172314fceff4SHauke Mehrtens 					unsigned int mode,
172414fceff4SHauke Mehrtens 					phy_interface_t interface)
172514fceff4SHauke Mehrtens {
172614fceff4SHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
172714fceff4SHauke Mehrtens 
172814fceff4SHauke Mehrtens 	gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, port);
17293e9005beSMartin Blumenstingl 
17303e9005beSMartin Blumenstingl 	if (!dsa_is_cpu_port(ds, port))
17313e9005beSMartin Blumenstingl 		gswip_port_set_link(priv, port, false);
173214fceff4SHauke Mehrtens }
173314fceff4SHauke Mehrtens 
gswip_phylink_mac_link_up(struct dsa_switch * ds,int port,unsigned int mode,phy_interface_t interface,struct phy_device * phydev,int speed,int duplex,bool tx_pause,bool rx_pause)173414fceff4SHauke Mehrtens static void gswip_phylink_mac_link_up(struct dsa_switch *ds, int port,
173514fceff4SHauke Mehrtens 				      unsigned int mode,
173614fceff4SHauke Mehrtens 				      phy_interface_t interface,
17375b502a7bSRussell King 				      struct phy_device *phydev,
17385b502a7bSRussell King 				      int speed, int duplex,
17395b502a7bSRussell King 				      bool tx_pause, bool rx_pause)
174014fceff4SHauke Mehrtens {
174114fceff4SHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
174214fceff4SHauke Mehrtens 
17433e9005beSMartin Blumenstingl 	if (!dsa_is_cpu_port(ds, port)) {
17443e9005beSMartin Blumenstingl 		gswip_port_set_link(priv, port, true);
17453e9005beSMartin Blumenstingl 		gswip_port_set_speed(priv, port, speed, interface);
17463e9005beSMartin Blumenstingl 		gswip_port_set_duplex(priv, port, duplex);
17473e9005beSMartin Blumenstingl 		gswip_port_set_pause(priv, port, tx_pause, rx_pause);
17483e9005beSMartin Blumenstingl 	}
17493e9005beSMartin Blumenstingl 
175014fceff4SHauke Mehrtens 	gswip_mii_mask_cfg(priv, 0, GSWIP_MII_CFG_EN, port);
175114fceff4SHauke Mehrtens }
175214fceff4SHauke Mehrtens 
gswip_get_strings(struct dsa_switch * ds,int port,u32 stringset,uint8_t * data)175314fceff4SHauke Mehrtens static void gswip_get_strings(struct dsa_switch *ds, int port, u32 stringset,
175414fceff4SHauke Mehrtens 			      uint8_t *data)
175514fceff4SHauke Mehrtens {
175614fceff4SHauke Mehrtens 	int i;
175714fceff4SHauke Mehrtens 
175814fceff4SHauke Mehrtens 	if (stringset != ETH_SS_STATS)
175914fceff4SHauke Mehrtens 		return;
176014fceff4SHauke Mehrtens 
176114fceff4SHauke Mehrtens 	for (i = 0; i < ARRAY_SIZE(gswip_rmon_cnt); i++)
176214fceff4SHauke Mehrtens 		strncpy(data + i * ETH_GSTRING_LEN, gswip_rmon_cnt[i].name,
176314fceff4SHauke Mehrtens 			ETH_GSTRING_LEN);
176414fceff4SHauke Mehrtens }
176514fceff4SHauke Mehrtens 
gswip_bcm_ram_entry_read(struct gswip_priv * priv,u32 table,u32 index)176614fceff4SHauke Mehrtens static u32 gswip_bcm_ram_entry_read(struct gswip_priv *priv, u32 table,
176714fceff4SHauke Mehrtens 				    u32 index)
176814fceff4SHauke Mehrtens {
176914fceff4SHauke Mehrtens 	u32 result;
177014fceff4SHauke Mehrtens 	int err;
177114fceff4SHauke Mehrtens 
177214fceff4SHauke Mehrtens 	gswip_switch_w(priv, index, GSWIP_BM_RAM_ADDR);
177314fceff4SHauke Mehrtens 	gswip_switch_mask(priv, GSWIP_BM_RAM_CTRL_ADDR_MASK |
177414fceff4SHauke Mehrtens 				GSWIP_BM_RAM_CTRL_OPMOD,
177514fceff4SHauke Mehrtens 			      table | GSWIP_BM_RAM_CTRL_BAS,
177614fceff4SHauke Mehrtens 			      GSWIP_BM_RAM_CTRL);
177714fceff4SHauke Mehrtens 
177814fceff4SHauke Mehrtens 	err = gswip_switch_r_timeout(priv, GSWIP_BM_RAM_CTRL,
177914fceff4SHauke Mehrtens 				     GSWIP_BM_RAM_CTRL_BAS);
178014fceff4SHauke Mehrtens 	if (err) {
178114fceff4SHauke Mehrtens 		dev_err(priv->dev, "timeout while reading table: %u, index: %u",
178214fceff4SHauke Mehrtens 			table, index);
178314fceff4SHauke Mehrtens 		return 0;
178414fceff4SHauke Mehrtens 	}
178514fceff4SHauke Mehrtens 
178614fceff4SHauke Mehrtens 	result = gswip_switch_r(priv, GSWIP_BM_RAM_VAL(0));
178714fceff4SHauke Mehrtens 	result |= gswip_switch_r(priv, GSWIP_BM_RAM_VAL(1)) << 16;
178814fceff4SHauke Mehrtens 
178914fceff4SHauke Mehrtens 	return result;
179014fceff4SHauke Mehrtens }
179114fceff4SHauke Mehrtens 
gswip_get_ethtool_stats(struct dsa_switch * ds,int port,uint64_t * data)179214fceff4SHauke Mehrtens static void gswip_get_ethtool_stats(struct dsa_switch *ds, int port,
179314fceff4SHauke Mehrtens 				    uint64_t *data)
179414fceff4SHauke Mehrtens {
179514fceff4SHauke Mehrtens 	struct gswip_priv *priv = ds->priv;
179614fceff4SHauke Mehrtens 	const struct gswip_rmon_cnt_desc *rmon_cnt;
179714fceff4SHauke Mehrtens 	int i;
179814fceff4SHauke Mehrtens 	u64 high;
179914fceff4SHauke Mehrtens 
180014fceff4SHauke Mehrtens 	for (i = 0; i < ARRAY_SIZE(gswip_rmon_cnt); i++) {
180114fceff4SHauke Mehrtens 		rmon_cnt = &gswip_rmon_cnt[i];
180214fceff4SHauke Mehrtens 
180314fceff4SHauke Mehrtens 		data[i] = gswip_bcm_ram_entry_read(priv, port,
180414fceff4SHauke Mehrtens 						   rmon_cnt->offset);
180514fceff4SHauke Mehrtens 		if (rmon_cnt->size == 2) {
180614fceff4SHauke Mehrtens 			high = gswip_bcm_ram_entry_read(priv, port,
180714fceff4SHauke Mehrtens 							rmon_cnt->offset + 1);
180814fceff4SHauke Mehrtens 			data[i] |= high << 32;
180914fceff4SHauke Mehrtens 		}
181014fceff4SHauke Mehrtens 	}
181114fceff4SHauke Mehrtens }
181214fceff4SHauke Mehrtens 
gswip_get_sset_count(struct dsa_switch * ds,int port,int sset)181314fceff4SHauke Mehrtens static int gswip_get_sset_count(struct dsa_switch *ds, int port, int sset)
181414fceff4SHauke Mehrtens {
181514fceff4SHauke Mehrtens 	if (sset != ETH_SS_STATS)
181614fceff4SHauke Mehrtens 		return 0;
181714fceff4SHauke Mehrtens 
181814fceff4SHauke Mehrtens 	return ARRAY_SIZE(gswip_rmon_cnt);
181914fceff4SHauke Mehrtens }
182014fceff4SHauke Mehrtens 
1821a09d042bSAleksander Jan Bajkowski static const struct dsa_switch_ops gswip_xrx200_switch_ops = {
182214fceff4SHauke Mehrtens 	.get_tag_protocol	= gswip_get_tag_protocol,
182314fceff4SHauke Mehrtens 	.setup			= gswip_setup,
182414fceff4SHauke Mehrtens 	.port_enable		= gswip_port_enable,
182514fceff4SHauke Mehrtens 	.port_disable		= gswip_port_disable,
18268206e0ceSHauke Mehrtens 	.port_bridge_join	= gswip_port_bridge_join,
18278206e0ceSHauke Mehrtens 	.port_bridge_leave	= gswip_port_bridge_leave,
182845813481SHauke Mehrtens 	.port_fast_age		= gswip_port_fast_age,
18299bbb1c05SHauke Mehrtens 	.port_vlan_filtering	= gswip_port_vlan_filtering,
18309bbb1c05SHauke Mehrtens 	.port_vlan_add		= gswip_port_vlan_add,
18319bbb1c05SHauke Mehrtens 	.port_vlan_del		= gswip_port_vlan_del,
18328206e0ceSHauke Mehrtens 	.port_stp_state_set	= gswip_port_stp_state_set,
183358c59ef9SHauke Mehrtens 	.port_fdb_add		= gswip_port_fdb_add,
183458c59ef9SHauke Mehrtens 	.port_fdb_del		= gswip_port_fdb_del,
183558c59ef9SHauke Mehrtens 	.port_fdb_dump		= gswip_port_fdb_dump,
1836c40bb4feSAleksander Jan Bajkowski 	.port_change_mtu	= gswip_port_change_mtu,
1837c40bb4feSAleksander Jan Bajkowski 	.port_max_mtu		= gswip_port_max_mtu,
1838a2279b08SRussell King (Oracle) 	.phylink_get_caps	= gswip_xrx200_phylink_get_caps,
1839a09d042bSAleksander Jan Bajkowski 	.phylink_mac_config	= gswip_phylink_mac_config,
1840a09d042bSAleksander Jan Bajkowski 	.phylink_mac_link_down	= gswip_phylink_mac_link_down,
1841a09d042bSAleksander Jan Bajkowski 	.phylink_mac_link_up	= gswip_phylink_mac_link_up,
1842a09d042bSAleksander Jan Bajkowski 	.get_strings		= gswip_get_strings,
1843a09d042bSAleksander Jan Bajkowski 	.get_ethtool_stats	= gswip_get_ethtool_stats,
1844a09d042bSAleksander Jan Bajkowski 	.get_sset_count		= gswip_get_sset_count,
1845a09d042bSAleksander Jan Bajkowski };
1846a09d042bSAleksander Jan Bajkowski 
1847a09d042bSAleksander Jan Bajkowski static const struct dsa_switch_ops gswip_xrx300_switch_ops = {
1848a09d042bSAleksander Jan Bajkowski 	.get_tag_protocol	= gswip_get_tag_protocol,
1849a09d042bSAleksander Jan Bajkowski 	.setup			= gswip_setup,
1850a09d042bSAleksander Jan Bajkowski 	.port_enable		= gswip_port_enable,
1851a09d042bSAleksander Jan Bajkowski 	.port_disable		= gswip_port_disable,
1852a09d042bSAleksander Jan Bajkowski 	.port_bridge_join	= gswip_port_bridge_join,
1853a09d042bSAleksander Jan Bajkowski 	.port_bridge_leave	= gswip_port_bridge_leave,
1854a09d042bSAleksander Jan Bajkowski 	.port_fast_age		= gswip_port_fast_age,
1855a09d042bSAleksander Jan Bajkowski 	.port_vlan_filtering	= gswip_port_vlan_filtering,
1856a09d042bSAleksander Jan Bajkowski 	.port_vlan_add		= gswip_port_vlan_add,
1857a09d042bSAleksander Jan Bajkowski 	.port_vlan_del		= gswip_port_vlan_del,
1858a09d042bSAleksander Jan Bajkowski 	.port_stp_state_set	= gswip_port_stp_state_set,
1859a09d042bSAleksander Jan Bajkowski 	.port_fdb_add		= gswip_port_fdb_add,
1860a09d042bSAleksander Jan Bajkowski 	.port_fdb_del		= gswip_port_fdb_del,
1861a09d042bSAleksander Jan Bajkowski 	.port_fdb_dump		= gswip_port_fdb_dump,
1862c40bb4feSAleksander Jan Bajkowski 	.port_change_mtu	= gswip_port_change_mtu,
1863c40bb4feSAleksander Jan Bajkowski 	.port_max_mtu		= gswip_port_max_mtu,
1864a2279b08SRussell King (Oracle) 	.phylink_get_caps	= gswip_xrx300_phylink_get_caps,
186514fceff4SHauke Mehrtens 	.phylink_mac_config	= gswip_phylink_mac_config,
186614fceff4SHauke Mehrtens 	.phylink_mac_link_down	= gswip_phylink_mac_link_down,
186714fceff4SHauke Mehrtens 	.phylink_mac_link_up	= gswip_phylink_mac_link_up,
186814fceff4SHauke Mehrtens 	.get_strings		= gswip_get_strings,
186914fceff4SHauke Mehrtens 	.get_ethtool_stats	= gswip_get_ethtool_stats,
187014fceff4SHauke Mehrtens 	.get_sset_count		= gswip_get_sset_count,
187114fceff4SHauke Mehrtens };
187214fceff4SHauke Mehrtens 
187314fceff4SHauke Mehrtens static const struct xway_gphy_match_data xrx200a1x_gphy_data = {
187414fceff4SHauke Mehrtens 	.fe_firmware_name = "lantiq/xrx200_phy22f_a14.bin",
187514fceff4SHauke Mehrtens 	.ge_firmware_name = "lantiq/xrx200_phy11g_a14.bin",
187614fceff4SHauke Mehrtens };
187714fceff4SHauke Mehrtens 
187814fceff4SHauke Mehrtens static const struct xway_gphy_match_data xrx200a2x_gphy_data = {
187914fceff4SHauke Mehrtens 	.fe_firmware_name = "lantiq/xrx200_phy22f_a22.bin",
188014fceff4SHauke Mehrtens 	.ge_firmware_name = "lantiq/xrx200_phy11g_a22.bin",
188114fceff4SHauke Mehrtens };
188214fceff4SHauke Mehrtens 
188314fceff4SHauke Mehrtens static const struct xway_gphy_match_data xrx300_gphy_data = {
188414fceff4SHauke Mehrtens 	.fe_firmware_name = "lantiq/xrx300_phy22f_a21.bin",
188514fceff4SHauke Mehrtens 	.ge_firmware_name = "lantiq/xrx300_phy11g_a21.bin",
188614fceff4SHauke Mehrtens };
188714fceff4SHauke Mehrtens 
1888*6ea1e677SKrzysztof Kozlowski static const struct of_device_id xway_gphy_match[] __maybe_unused = {
188914fceff4SHauke Mehrtens 	{ .compatible = "lantiq,xrx200-gphy-fw", .data = NULL },
189014fceff4SHauke Mehrtens 	{ .compatible = "lantiq,xrx200a1x-gphy-fw", .data = &xrx200a1x_gphy_data },
189114fceff4SHauke Mehrtens 	{ .compatible = "lantiq,xrx200a2x-gphy-fw", .data = &xrx200a2x_gphy_data },
189214fceff4SHauke Mehrtens 	{ .compatible = "lantiq,xrx300-gphy-fw", .data = &xrx300_gphy_data },
189314fceff4SHauke Mehrtens 	{ .compatible = "lantiq,xrx330-gphy-fw", .data = &xrx300_gphy_data },
189414fceff4SHauke Mehrtens 	{},
189514fceff4SHauke Mehrtens };
189614fceff4SHauke Mehrtens 
gswip_gphy_fw_load(struct gswip_priv * priv,struct gswip_gphy_fw * gphy_fw)189714fceff4SHauke Mehrtens static int gswip_gphy_fw_load(struct gswip_priv *priv, struct gswip_gphy_fw *gphy_fw)
189814fceff4SHauke Mehrtens {
189914fceff4SHauke Mehrtens 	struct device *dev = priv->dev;
190014fceff4SHauke Mehrtens 	const struct firmware *fw;
190114fceff4SHauke Mehrtens 	void *fw_addr;
190214fceff4SHauke Mehrtens 	dma_addr_t dma_addr;
190314fceff4SHauke Mehrtens 	dma_addr_t dev_addr;
190414fceff4SHauke Mehrtens 	size_t size;
190514fceff4SHauke Mehrtens 	int ret;
190614fceff4SHauke Mehrtens 
190714fceff4SHauke Mehrtens 	ret = clk_prepare_enable(gphy_fw->clk_gate);
190814fceff4SHauke Mehrtens 	if (ret)
190914fceff4SHauke Mehrtens 		return ret;
191014fceff4SHauke Mehrtens 
191114fceff4SHauke Mehrtens 	reset_control_assert(gphy_fw->reset);
191214fceff4SHauke Mehrtens 
1913111b64e3SAleksander Jan Bajkowski 	/* The vendor BSP uses a 200ms delay after asserting the reset line.
1914111b64e3SAleksander Jan Bajkowski 	 * Without this some users are observing that the PHY is not coming up
1915111b64e3SAleksander Jan Bajkowski 	 * on the MDIO bus.
1916111b64e3SAleksander Jan Bajkowski 	 */
1917111b64e3SAleksander Jan Bajkowski 	msleep(200);
1918111b64e3SAleksander Jan Bajkowski 
191914fceff4SHauke Mehrtens 	ret = request_firmware(&fw, gphy_fw->fw_name, dev);
192014fceff4SHauke Mehrtens 	if (ret) {
192114fceff4SHauke Mehrtens 		dev_err(dev, "failed to load firmware: %s, error: %i\n",
192214fceff4SHauke Mehrtens 			gphy_fw->fw_name, ret);
192314fceff4SHauke Mehrtens 		return ret;
192414fceff4SHauke Mehrtens 	}
192514fceff4SHauke Mehrtens 
192614fceff4SHauke Mehrtens 	/* GPHY cores need the firmware code in a persistent and contiguous
192714fceff4SHauke Mehrtens 	 * memory area with a 16 kB boundary aligned start address.
192814fceff4SHauke Mehrtens 	 */
192914fceff4SHauke Mehrtens 	size = fw->size + XRX200_GPHY_FW_ALIGN;
193014fceff4SHauke Mehrtens 
193114fceff4SHauke Mehrtens 	fw_addr = dmam_alloc_coherent(dev, size, &dma_addr, GFP_KERNEL);
193214fceff4SHauke Mehrtens 	if (fw_addr) {
193314fceff4SHauke Mehrtens 		fw_addr = PTR_ALIGN(fw_addr, XRX200_GPHY_FW_ALIGN);
193414fceff4SHauke Mehrtens 		dev_addr = ALIGN(dma_addr, XRX200_GPHY_FW_ALIGN);
193514fceff4SHauke Mehrtens 		memcpy(fw_addr, fw->data, fw->size);
193614fceff4SHauke Mehrtens 	} else {
193714fceff4SHauke Mehrtens 		dev_err(dev, "failed to alloc firmware memory\n");
193814fceff4SHauke Mehrtens 		release_firmware(fw);
193914fceff4SHauke Mehrtens 		return -ENOMEM;
194014fceff4SHauke Mehrtens 	}
194114fceff4SHauke Mehrtens 
194214fceff4SHauke Mehrtens 	release_firmware(fw);
194314fceff4SHauke Mehrtens 
194414fceff4SHauke Mehrtens 	ret = regmap_write(priv->rcu_regmap, gphy_fw->fw_addr_offset, dev_addr);
194514fceff4SHauke Mehrtens 	if (ret)
194614fceff4SHauke Mehrtens 		return ret;
194714fceff4SHauke Mehrtens 
194814fceff4SHauke Mehrtens 	reset_control_deassert(gphy_fw->reset);
194914fceff4SHauke Mehrtens 
195014fceff4SHauke Mehrtens 	return ret;
195114fceff4SHauke Mehrtens }
195214fceff4SHauke Mehrtens 
gswip_gphy_fw_probe(struct gswip_priv * priv,struct gswip_gphy_fw * gphy_fw,struct device_node * gphy_fw_np,int i)195314fceff4SHauke Mehrtens static int gswip_gphy_fw_probe(struct gswip_priv *priv,
195414fceff4SHauke Mehrtens 			       struct gswip_gphy_fw *gphy_fw,
195514fceff4SHauke Mehrtens 			       struct device_node *gphy_fw_np, int i)
195614fceff4SHauke Mehrtens {
195714fceff4SHauke Mehrtens 	struct device *dev = priv->dev;
195814fceff4SHauke Mehrtens 	u32 gphy_mode;
195914fceff4SHauke Mehrtens 	int ret;
196014fceff4SHauke Mehrtens 	char gphyname[10];
196114fceff4SHauke Mehrtens 
196214fceff4SHauke Mehrtens 	snprintf(gphyname, sizeof(gphyname), "gphy%d", i);
196314fceff4SHauke Mehrtens 
196414fceff4SHauke Mehrtens 	gphy_fw->clk_gate = devm_clk_get(dev, gphyname);
196514fceff4SHauke Mehrtens 	if (IS_ERR(gphy_fw->clk_gate)) {
196614fceff4SHauke Mehrtens 		dev_err(dev, "Failed to lookup gate clock\n");
196714fceff4SHauke Mehrtens 		return PTR_ERR(gphy_fw->clk_gate);
196814fceff4SHauke Mehrtens 	}
196914fceff4SHauke Mehrtens 
197014fceff4SHauke Mehrtens 	ret = of_property_read_u32(gphy_fw_np, "reg", &gphy_fw->fw_addr_offset);
197114fceff4SHauke Mehrtens 	if (ret)
197214fceff4SHauke Mehrtens 		return ret;
197314fceff4SHauke Mehrtens 
197414fceff4SHauke Mehrtens 	ret = of_property_read_u32(gphy_fw_np, "lantiq,gphy-mode", &gphy_mode);
197514fceff4SHauke Mehrtens 	/* Default to GE mode */
197614fceff4SHauke Mehrtens 	if (ret)
197714fceff4SHauke Mehrtens 		gphy_mode = GPHY_MODE_GE;
197814fceff4SHauke Mehrtens 
197914fceff4SHauke Mehrtens 	switch (gphy_mode) {
198014fceff4SHauke Mehrtens 	case GPHY_MODE_FE:
198114fceff4SHauke Mehrtens 		gphy_fw->fw_name = priv->gphy_fw_name_cfg->fe_firmware_name;
198214fceff4SHauke Mehrtens 		break;
198314fceff4SHauke Mehrtens 	case GPHY_MODE_GE:
198414fceff4SHauke Mehrtens 		gphy_fw->fw_name = priv->gphy_fw_name_cfg->ge_firmware_name;
198514fceff4SHauke Mehrtens 		break;
198614fceff4SHauke Mehrtens 	default:
198714fceff4SHauke Mehrtens 		dev_err(dev, "Unknown GPHY mode %d\n", gphy_mode);
198814fceff4SHauke Mehrtens 		return -EINVAL;
198914fceff4SHauke Mehrtens 	}
199014fceff4SHauke Mehrtens 
199114fceff4SHauke Mehrtens 	gphy_fw->reset = of_reset_control_array_get_exclusive(gphy_fw_np);
1992d02bb8beSYang Yingliang 	if (IS_ERR(gphy_fw->reset))
1993d02bb8beSYang Yingliang 		return dev_err_probe(dev, PTR_ERR(gphy_fw->reset),
1994d02bb8beSYang Yingliang 				     "Failed to lookup gphy reset\n");
199514fceff4SHauke Mehrtens 
199614fceff4SHauke Mehrtens 	return gswip_gphy_fw_load(priv, gphy_fw);
199714fceff4SHauke Mehrtens }
199814fceff4SHauke Mehrtens 
gswip_gphy_fw_remove(struct gswip_priv * priv,struct gswip_gphy_fw * gphy_fw)199914fceff4SHauke Mehrtens static void gswip_gphy_fw_remove(struct gswip_priv *priv,
200014fceff4SHauke Mehrtens 				 struct gswip_gphy_fw *gphy_fw)
200114fceff4SHauke Mehrtens {
200214fceff4SHauke Mehrtens 	int ret;
200314fceff4SHauke Mehrtens 
200414fceff4SHauke Mehrtens 	/* check if the device was fully probed */
200514fceff4SHauke Mehrtens 	if (!gphy_fw->fw_name)
200614fceff4SHauke Mehrtens 		return;
200714fceff4SHauke Mehrtens 
200814fceff4SHauke Mehrtens 	ret = regmap_write(priv->rcu_regmap, gphy_fw->fw_addr_offset, 0);
200914fceff4SHauke Mehrtens 	if (ret)
201014fceff4SHauke Mehrtens 		dev_err(priv->dev, "can not reset GPHY FW pointer");
201114fceff4SHauke Mehrtens 
201214fceff4SHauke Mehrtens 	clk_disable_unprepare(gphy_fw->clk_gate);
201314fceff4SHauke Mehrtens 
201414fceff4SHauke Mehrtens 	reset_control_put(gphy_fw->reset);
201514fceff4SHauke Mehrtens }
201614fceff4SHauke Mehrtens 
gswip_gphy_fw_list(struct gswip_priv * priv,struct device_node * gphy_fw_list_np,u32 version)201714fceff4SHauke Mehrtens static int gswip_gphy_fw_list(struct gswip_priv *priv,
201814fceff4SHauke Mehrtens 			      struct device_node *gphy_fw_list_np, u32 version)
201914fceff4SHauke Mehrtens {
202014fceff4SHauke Mehrtens 	struct device *dev = priv->dev;
202114fceff4SHauke Mehrtens 	struct device_node *gphy_fw_np;
202214fceff4SHauke Mehrtens 	const struct of_device_id *match;
202314fceff4SHauke Mehrtens 	int err;
202414fceff4SHauke Mehrtens 	int i = 0;
202514fceff4SHauke Mehrtens 
20260e630b59SHauke Mehrtens 	/* The VRX200 rev 1.1 uses the GSWIP 2.0 and needs the older
202714fceff4SHauke Mehrtens 	 * GPHY firmware. The VRX200 rev 1.2 uses the GSWIP 2.1 and also
202814fceff4SHauke Mehrtens 	 * needs a different GPHY firmware.
202914fceff4SHauke Mehrtens 	 */
203014fceff4SHauke Mehrtens 	if (of_device_is_compatible(gphy_fw_list_np, "lantiq,xrx200-gphy-fw")) {
203114fceff4SHauke Mehrtens 		switch (version) {
203214fceff4SHauke Mehrtens 		case GSWIP_VERSION_2_0:
203314fceff4SHauke Mehrtens 			priv->gphy_fw_name_cfg = &xrx200a1x_gphy_data;
203414fceff4SHauke Mehrtens 			break;
203514fceff4SHauke Mehrtens 		case GSWIP_VERSION_2_1:
203614fceff4SHauke Mehrtens 			priv->gphy_fw_name_cfg = &xrx200a2x_gphy_data;
203714fceff4SHauke Mehrtens 			break;
203814fceff4SHauke Mehrtens 		default:
203914fceff4SHauke Mehrtens 			dev_err(dev, "unknown GSWIP version: 0x%x", version);
204014fceff4SHauke Mehrtens 			return -ENOENT;
204114fceff4SHauke Mehrtens 		}
204214fceff4SHauke Mehrtens 	}
204314fceff4SHauke Mehrtens 
204414fceff4SHauke Mehrtens 	match = of_match_node(xway_gphy_match, gphy_fw_list_np);
204514fceff4SHauke Mehrtens 	if (match && match->data)
204614fceff4SHauke Mehrtens 		priv->gphy_fw_name_cfg = match->data;
204714fceff4SHauke Mehrtens 
204814fceff4SHauke Mehrtens 	if (!priv->gphy_fw_name_cfg) {
204914fceff4SHauke Mehrtens 		dev_err(dev, "GPHY compatible type not supported");
205014fceff4SHauke Mehrtens 		return -ENOENT;
205114fceff4SHauke Mehrtens 	}
205214fceff4SHauke Mehrtens 
205314fceff4SHauke Mehrtens 	priv->num_gphy_fw = of_get_available_child_count(gphy_fw_list_np);
205414fceff4SHauke Mehrtens 	if (!priv->num_gphy_fw)
205514fceff4SHauke Mehrtens 		return -ENOENT;
205614fceff4SHauke Mehrtens 
205714fceff4SHauke Mehrtens 	priv->rcu_regmap = syscon_regmap_lookup_by_phandle(gphy_fw_list_np,
205814fceff4SHauke Mehrtens 							   "lantiq,rcu");
205914fceff4SHauke Mehrtens 	if (IS_ERR(priv->rcu_regmap))
206014fceff4SHauke Mehrtens 		return PTR_ERR(priv->rcu_regmap);
206114fceff4SHauke Mehrtens 
206214fceff4SHauke Mehrtens 	priv->gphy_fw = devm_kmalloc_array(dev, priv->num_gphy_fw,
206314fceff4SHauke Mehrtens 					   sizeof(*priv->gphy_fw),
206414fceff4SHauke Mehrtens 					   GFP_KERNEL | __GFP_ZERO);
206514fceff4SHauke Mehrtens 	if (!priv->gphy_fw)
206614fceff4SHauke Mehrtens 		return -ENOMEM;
206714fceff4SHauke Mehrtens 
206814fceff4SHauke Mehrtens 	for_each_available_child_of_node(gphy_fw_list_np, gphy_fw_np) {
206914fceff4SHauke Mehrtens 		err = gswip_gphy_fw_probe(priv, &priv->gphy_fw[i],
207014fceff4SHauke Mehrtens 					  gphy_fw_np, i);
20710737e018SMiaoqian Lin 		if (err) {
20720737e018SMiaoqian Lin 			of_node_put(gphy_fw_np);
207314fceff4SHauke Mehrtens 			goto remove_gphy;
20740737e018SMiaoqian Lin 		}
207514fceff4SHauke Mehrtens 		i++;
207614fceff4SHauke Mehrtens 	}
207714fceff4SHauke Mehrtens 
20782a1828e3SMartin Blumenstingl 	/* The standalone PHY11G requires 300ms to be fully
20792a1828e3SMartin Blumenstingl 	 * initialized and ready for any MDIO communication after being
20802a1828e3SMartin Blumenstingl 	 * taken out of reset. For the SoC-internal GPHY variant there
20812a1828e3SMartin Blumenstingl 	 * is no (known) documentation for the minimum time after a
20822a1828e3SMartin Blumenstingl 	 * reset. Use the same value as for the standalone variant as
20832a1828e3SMartin Blumenstingl 	 * some users have reported internal PHYs not being detected
20842a1828e3SMartin Blumenstingl 	 * without any delay.
20852a1828e3SMartin Blumenstingl 	 */
20862a1828e3SMartin Blumenstingl 	msleep(300);
20872a1828e3SMartin Blumenstingl 
208814fceff4SHauke Mehrtens 	return 0;
208914fceff4SHauke Mehrtens 
209014fceff4SHauke Mehrtens remove_gphy:
209114fceff4SHauke Mehrtens 	for (i = 0; i < priv->num_gphy_fw; i++)
209214fceff4SHauke Mehrtens 		gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]);
209314fceff4SHauke Mehrtens 	return err;
209414fceff4SHauke Mehrtens }
209514fceff4SHauke Mehrtens 
gswip_probe(struct platform_device * pdev)209614fceff4SHauke Mehrtens static int gswip_probe(struct platform_device *pdev)
209714fceff4SHauke Mehrtens {
209814fceff4SHauke Mehrtens 	struct gswip_priv *priv;
2099204c7614SAleksander Jan Bajkowski 	struct device_node *np, *mdio_np, *gphy_fw_np;
210014fceff4SHauke Mehrtens 	struct device *dev = &pdev->dev;
210114fceff4SHauke Mehrtens 	int err;
210214fceff4SHauke Mehrtens 	int i;
210314fceff4SHauke Mehrtens 	u32 version;
210414fceff4SHauke Mehrtens 
210514fceff4SHauke Mehrtens 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
210614fceff4SHauke Mehrtens 	if (!priv)
210714fceff4SHauke Mehrtens 		return -ENOMEM;
210814fceff4SHauke Mehrtens 
21096551c8c8SYueHaibing 	priv->gswip = devm_platform_ioremap_resource(pdev, 0);
2110f5de8bfeSWei Yongjun 	if (IS_ERR(priv->gswip))
2111f5de8bfeSWei Yongjun 		return PTR_ERR(priv->gswip);
211214fceff4SHauke Mehrtens 
21136551c8c8SYueHaibing 	priv->mdio = devm_platform_ioremap_resource(pdev, 1);
2114f5de8bfeSWei Yongjun 	if (IS_ERR(priv->mdio))
2115f5de8bfeSWei Yongjun 		return PTR_ERR(priv->mdio);
211614fceff4SHauke Mehrtens 
21176551c8c8SYueHaibing 	priv->mii = devm_platform_ioremap_resource(pdev, 2);
2118f5de8bfeSWei Yongjun 	if (IS_ERR(priv->mii))
2119f5de8bfeSWei Yongjun 		return PTR_ERR(priv->mii);
212014fceff4SHauke Mehrtens 
212114fceff4SHauke Mehrtens 	priv->hw_info = of_device_get_match_data(dev);
212214fceff4SHauke Mehrtens 	if (!priv->hw_info)
212314fceff4SHauke Mehrtens 		return -EINVAL;
212414fceff4SHauke Mehrtens 
21257e99e347SVivien Didelot 	priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL);
212614fceff4SHauke Mehrtens 	if (!priv->ds)
212714fceff4SHauke Mehrtens 		return -ENOMEM;
212814fceff4SHauke Mehrtens 
21297e99e347SVivien Didelot 	priv->ds->dev = dev;
21307e99e347SVivien Didelot 	priv->ds->num_ports = priv->hw_info->max_ports;
213114fceff4SHauke Mehrtens 	priv->ds->priv = priv;
2132a09d042bSAleksander Jan Bajkowski 	priv->ds->ops = priv->hw_info->ops;
213314fceff4SHauke Mehrtens 	priv->dev = dev;
2134cf231b43SVladimir Oltean 	mutex_init(&priv->pce_table_lock);
213514fceff4SHauke Mehrtens 	version = gswip_switch_r(priv, GSWIP_VERSION);
213614fceff4SHauke Mehrtens 
2137204c7614SAleksander Jan Bajkowski 	np = dev->of_node;
2138204c7614SAleksander Jan Bajkowski 	switch (version) {
2139204c7614SAleksander Jan Bajkowski 	case GSWIP_VERSION_2_0:
2140204c7614SAleksander Jan Bajkowski 	case GSWIP_VERSION_2_1:
2141204c7614SAleksander Jan Bajkowski 		if (!of_device_is_compatible(np, "lantiq,xrx200-gswip"))
2142204c7614SAleksander Jan Bajkowski 			return -EINVAL;
2143204c7614SAleksander Jan Bajkowski 		break;
2144204c7614SAleksander Jan Bajkowski 	case GSWIP_VERSION_2_2:
2145204c7614SAleksander Jan Bajkowski 	case GSWIP_VERSION_2_2_ETC:
2146204c7614SAleksander Jan Bajkowski 		if (!of_device_is_compatible(np, "lantiq,xrx300-gswip") &&
2147204c7614SAleksander Jan Bajkowski 		    !of_device_is_compatible(np, "lantiq,xrx330-gswip"))
2148204c7614SAleksander Jan Bajkowski 			return -EINVAL;
2149204c7614SAleksander Jan Bajkowski 		break;
2150204c7614SAleksander Jan Bajkowski 	default:
2151204c7614SAleksander Jan Bajkowski 		dev_err(dev, "unknown GSWIP version: 0x%x", version);
2152204c7614SAleksander Jan Bajkowski 		return -ENOENT;
2153204c7614SAleksander Jan Bajkowski 	}
2154204c7614SAleksander Jan Bajkowski 
215514fceff4SHauke Mehrtens 	/* bring up the mdio bus */
2156c8cbcb0dSJohan Hovold 	gphy_fw_np = of_get_compatible_child(dev->of_node, "lantiq,gphy-fw");
215714fceff4SHauke Mehrtens 	if (gphy_fw_np) {
215814fceff4SHauke Mehrtens 		err = gswip_gphy_fw_list(priv, gphy_fw_np, version);
2159c8cbcb0dSJohan Hovold 		of_node_put(gphy_fw_np);
216014fceff4SHauke Mehrtens 		if (err) {
216114fceff4SHauke Mehrtens 			dev_err(dev, "gphy fw probe failed\n");
216214fceff4SHauke Mehrtens 			return err;
216314fceff4SHauke Mehrtens 		}
216414fceff4SHauke Mehrtens 	}
216514fceff4SHauke Mehrtens 
216614fceff4SHauke Mehrtens 	/* bring up the mdio bus */
2167c8cbcb0dSJohan Hovold 	mdio_np = of_get_compatible_child(dev->of_node, "lantiq,xrx200-mdio");
216814fceff4SHauke Mehrtens 	if (mdio_np) {
216914fceff4SHauke Mehrtens 		err = gswip_mdio(priv, mdio_np);
217014fceff4SHauke Mehrtens 		if (err) {
217114fceff4SHauke Mehrtens 			dev_err(dev, "mdio probe failed\n");
2172c8cbcb0dSJohan Hovold 			goto put_mdio_node;
217314fceff4SHauke Mehrtens 		}
217414fceff4SHauke Mehrtens 	}
217514fceff4SHauke Mehrtens 
217614fceff4SHauke Mehrtens 	err = dsa_register_switch(priv->ds);
217714fceff4SHauke Mehrtens 	if (err) {
217814fceff4SHauke Mehrtens 		dev_err(dev, "dsa switch register failed: %i\n", err);
217914fceff4SHauke Mehrtens 		goto mdio_bus;
218014fceff4SHauke Mehrtens 	}
21810e630b59SHauke Mehrtens 	if (!dsa_is_cpu_port(priv->ds, priv->hw_info->cpu_port)) {
218214fceff4SHauke Mehrtens 		dev_err(dev, "wrong CPU port defined, HW only supports port: %i",
218314fceff4SHauke Mehrtens 			priv->hw_info->cpu_port);
218414fceff4SHauke Mehrtens 		err = -EINVAL;
2185aed13f2eSJohan Hovold 		goto disable_switch;
218614fceff4SHauke Mehrtens 	}
218714fceff4SHauke Mehrtens 
218814fceff4SHauke Mehrtens 	platform_set_drvdata(pdev, priv);
218914fceff4SHauke Mehrtens 
219014fceff4SHauke Mehrtens 	dev_info(dev, "probed GSWIP version %lx mod %lx\n",
219114fceff4SHauke Mehrtens 		 (version & GSWIP_VERSION_REV_MASK) >> GSWIP_VERSION_REV_SHIFT,
219214fceff4SHauke Mehrtens 		 (version & GSWIP_VERSION_MOD_MASK) >> GSWIP_VERSION_MOD_SHIFT);
219314fceff4SHauke Mehrtens 	return 0;
219414fceff4SHauke Mehrtens 
2195aed13f2eSJohan Hovold disable_switch:
2196aed13f2eSJohan Hovold 	gswip_mdio_mask(priv, GSWIP_MDIO_GLOB_ENABLE, 0, GSWIP_MDIO_GLOB);
2197aed13f2eSJohan Hovold 	dsa_unregister_switch(priv->ds);
219814fceff4SHauke Mehrtens mdio_bus:
21990d120dfbSVladimir Oltean 	if (mdio_np) {
220014fceff4SHauke Mehrtens 		mdiobus_unregister(priv->ds->slave_mii_bus);
22010d120dfbSVladimir Oltean 		mdiobus_free(priv->ds->slave_mii_bus);
22020d120dfbSVladimir Oltean 	}
2203c8cbcb0dSJohan Hovold put_mdio_node:
2204c8cbcb0dSJohan Hovold 	of_node_put(mdio_np);
220514fceff4SHauke Mehrtens 	for (i = 0; i < priv->num_gphy_fw; i++)
220614fceff4SHauke Mehrtens 		gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]);
220714fceff4SHauke Mehrtens 	return err;
220814fceff4SHauke Mehrtens }
220914fceff4SHauke Mehrtens 
gswip_remove(struct platform_device * pdev)221014fceff4SHauke Mehrtens static int gswip_remove(struct platform_device *pdev)
221114fceff4SHauke Mehrtens {
221214fceff4SHauke Mehrtens 	struct gswip_priv *priv = platform_get_drvdata(pdev);
221314fceff4SHauke Mehrtens 	int i;
221414fceff4SHauke Mehrtens 
22150650bf52SVladimir Oltean 	if (!priv)
22160650bf52SVladimir Oltean 		return 0;
22170650bf52SVladimir Oltean 
221814fceff4SHauke Mehrtens 	/* disable the switch */
221914fceff4SHauke Mehrtens 	gswip_mdio_mask(priv, GSWIP_MDIO_GLOB_ENABLE, 0, GSWIP_MDIO_GLOB);
222014fceff4SHauke Mehrtens 
222114fceff4SHauke Mehrtens 	dsa_unregister_switch(priv->ds);
222214fceff4SHauke Mehrtens 
2223c8cbcb0dSJohan Hovold 	if (priv->ds->slave_mii_bus) {
222414fceff4SHauke Mehrtens 		mdiobus_unregister(priv->ds->slave_mii_bus);
2225c8cbcb0dSJohan Hovold 		of_node_put(priv->ds->slave_mii_bus->dev.of_node);
22268c6ae461SAlexey Khoroshilov 		mdiobus_free(priv->ds->slave_mii_bus);
2227c8cbcb0dSJohan Hovold 	}
222814fceff4SHauke Mehrtens 
222914fceff4SHauke Mehrtens 	for (i = 0; i < priv->num_gphy_fw; i++)
223014fceff4SHauke Mehrtens 		gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]);
223114fceff4SHauke Mehrtens 
223214fceff4SHauke Mehrtens 	return 0;
223314fceff4SHauke Mehrtens }
223414fceff4SHauke Mehrtens 
gswip_shutdown(struct platform_device * pdev)22350650bf52SVladimir Oltean static void gswip_shutdown(struct platform_device *pdev)
22360650bf52SVladimir Oltean {
22370650bf52SVladimir Oltean 	struct gswip_priv *priv = platform_get_drvdata(pdev);
22380650bf52SVladimir Oltean 
22390650bf52SVladimir Oltean 	if (!priv)
22400650bf52SVladimir Oltean 		return;
22410650bf52SVladimir Oltean 
22420650bf52SVladimir Oltean 	dsa_switch_shutdown(priv->ds);
22430650bf52SVladimir Oltean 
22440650bf52SVladimir Oltean 	platform_set_drvdata(pdev, NULL);
22450650bf52SVladimir Oltean }
22460650bf52SVladimir Oltean 
224714fceff4SHauke Mehrtens static const struct gswip_hw_info gswip_xrx200 = {
224814fceff4SHauke Mehrtens 	.max_ports = 7,
224914fceff4SHauke Mehrtens 	.cpu_port = 6,
2250a09d042bSAleksander Jan Bajkowski 	.ops = &gswip_xrx200_switch_ops,
2251a09d042bSAleksander Jan Bajkowski };
2252a09d042bSAleksander Jan Bajkowski 
2253a09d042bSAleksander Jan Bajkowski static const struct gswip_hw_info gswip_xrx300 = {
2254a09d042bSAleksander Jan Bajkowski 	.max_ports = 7,
2255a09d042bSAleksander Jan Bajkowski 	.cpu_port = 6,
2256a09d042bSAleksander Jan Bajkowski 	.ops = &gswip_xrx300_switch_ops,
225714fceff4SHauke Mehrtens };
225814fceff4SHauke Mehrtens 
225914fceff4SHauke Mehrtens static const struct of_device_id gswip_of_match[] = {
226014fceff4SHauke Mehrtens 	{ .compatible = "lantiq,xrx200-gswip", .data = &gswip_xrx200 },
2261a09d042bSAleksander Jan Bajkowski 	{ .compatible = "lantiq,xrx300-gswip", .data = &gswip_xrx300 },
2262a09d042bSAleksander Jan Bajkowski 	{ .compatible = "lantiq,xrx330-gswip", .data = &gswip_xrx300 },
226314fceff4SHauke Mehrtens 	{},
226414fceff4SHauke Mehrtens };
226514fceff4SHauke Mehrtens MODULE_DEVICE_TABLE(of, gswip_of_match);
226614fceff4SHauke Mehrtens 
226714fceff4SHauke Mehrtens static struct platform_driver gswip_driver = {
226814fceff4SHauke Mehrtens 	.probe = gswip_probe,
226914fceff4SHauke Mehrtens 	.remove = gswip_remove,
22700650bf52SVladimir Oltean 	.shutdown = gswip_shutdown,
227114fceff4SHauke Mehrtens 	.driver = {
227214fceff4SHauke Mehrtens 		.name = "gswip",
227314fceff4SHauke Mehrtens 		.of_match_table = gswip_of_match,
227414fceff4SHauke Mehrtens 	},
227514fceff4SHauke Mehrtens };
227614fceff4SHauke Mehrtens 
227714fceff4SHauke Mehrtens module_platform_driver(gswip_driver);
227814fceff4SHauke Mehrtens 
2279cffde201SHauke Mehrtens MODULE_FIRMWARE("lantiq/xrx300_phy11g_a21.bin");
2280cffde201SHauke Mehrtens MODULE_FIRMWARE("lantiq/xrx300_phy22f_a21.bin");
2281cffde201SHauke Mehrtens MODULE_FIRMWARE("lantiq/xrx200_phy11g_a14.bin");
2282cffde201SHauke Mehrtens MODULE_FIRMWARE("lantiq/xrx200_phy11g_a22.bin");
2283cffde201SHauke Mehrtens MODULE_FIRMWARE("lantiq/xrx200_phy22f_a14.bin");
2284cffde201SHauke Mehrtens MODULE_FIRMWARE("lantiq/xrx200_phy22f_a22.bin");
228514fceff4SHauke Mehrtens MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
228614fceff4SHauke Mehrtens MODULE_DESCRIPTION("Lantiq / Intel GSWIP driver");
228714fceff4SHauke Mehrtens MODULE_LICENSE("GPL v2");
2288