diff options
Diffstat (limited to 'drivers/net/dsa/lantiq_gswip.c')
| -rw-r--r-- | drivers/net/dsa/lantiq_gswip.c | 357 | 
1 files changed, 305 insertions, 52 deletions
| diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index 52e865a3912c..314ae78bbdd6 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0  /* - * Lantiq / Intel GSWIP switch driver for VRX200 SoCs + * Lantiq / Intel GSWIP switch driver for VRX200, xRX300 and xRX330 SoCs   *   * Copyright (C) 2010 Lantiq Deutschland   * Copyright (C) 2012 John Crispin <john@phrozen.org> @@ -93,13 +93,18 @@  /* GSWIP MII Registers */  #define GSWIP_MII_CFGp(p)		(0x2 * (p)) +#define  GSWIP_MII_CFG_RESET		BIT(15)  #define  GSWIP_MII_CFG_EN		BIT(14) +#define  GSWIP_MII_CFG_ISOLATE		BIT(13)  #define  GSWIP_MII_CFG_LDCLKDIS		BIT(12) +#define  GSWIP_MII_CFG_RGMII_IBS	BIT(8) +#define  GSWIP_MII_CFG_RMII_CLK		BIT(7)  #define  GSWIP_MII_CFG_MODE_MIIP	0x0  #define  GSWIP_MII_CFG_MODE_MIIM	0x1  #define  GSWIP_MII_CFG_MODE_RMIIP	0x2  #define  GSWIP_MII_CFG_MODE_RMIIM	0x3  #define  GSWIP_MII_CFG_MODE_RGMII	0x4 +#define  GSWIP_MII_CFG_MODE_GMII	0x9  #define  GSWIP_MII_CFG_MODE_MASK	0xf  #define  GSWIP_MII_CFG_RATE_M2P5	0x00  #define  GSWIP_MII_CFG_RATE_M25	0x10 @@ -190,6 +195,23 @@  #define GSWIP_PCE_DEFPVID(p)		(0x486 + ((p) * 0xA))  #define GSWIP_MAC_FLEN			0x8C5 +#define GSWIP_MAC_CTRL_0p(p)		(0x903 + ((p) * 0xC)) +#define  GSWIP_MAC_CTRL_0_PADEN		BIT(8) +#define  GSWIP_MAC_CTRL_0_FCS_EN	BIT(7) +#define  GSWIP_MAC_CTRL_0_FCON_MASK	0x0070 +#define  GSWIP_MAC_CTRL_0_FCON_AUTO	0x0000 +#define  GSWIP_MAC_CTRL_0_FCON_RX	0x0010 +#define  GSWIP_MAC_CTRL_0_FCON_TX	0x0020 +#define  GSWIP_MAC_CTRL_0_FCON_RXTX	0x0030 +#define  GSWIP_MAC_CTRL_0_FCON_NONE	0x0040 +#define  GSWIP_MAC_CTRL_0_FDUP_MASK	0x000C +#define  GSWIP_MAC_CTRL_0_FDUP_AUTO	0x0000 +#define  GSWIP_MAC_CTRL_0_FDUP_EN	0x0004 +#define  GSWIP_MAC_CTRL_0_FDUP_DIS	0x000C +#define  GSWIP_MAC_CTRL_0_GMII_MASK	0x0003 +#define  GSWIP_MAC_CTRL_0_GMII_AUTO	0x0000 +#define  GSWIP_MAC_CTRL_0_GMII_MII	0x0001 +#define  GSWIP_MAC_CTRL_0_GMII_RGMII	0x0002  #define GSWIP_MAC_CTRL_2p(p)		(0x905 + ((p) * 0xC))  #define GSWIP_MAC_CTRL_2_MLEN		BIT(3) /* Maximum Untagged Frame Lnegth */ @@ -220,6 +242,7 @@  struct gswip_hw_info {  	int max_ports;  	int cpu_port; +	const struct dsa_switch_ops *ops;  };  struct xway_gphy_match_data { @@ -653,16 +676,13 @@ static int gswip_port_enable(struct dsa_switch *ds, int port,  			  GSWIP_SDMA_PCTRLp(port));  	if (!dsa_is_cpu_port(ds, port)) { -		u32 macconf = GSWIP_MDIO_PHY_LINK_AUTO | -			      GSWIP_MDIO_PHY_SPEED_AUTO | -			      GSWIP_MDIO_PHY_FDUP_AUTO | -			      GSWIP_MDIO_PHY_FCONTX_AUTO | -			      GSWIP_MDIO_PHY_FCONRX_AUTO | -			      (phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK); - -		gswip_mdio_w(priv, macconf, GSWIP_MDIO_PHYp(port)); -		/* Activate MDIO auto polling */ -		gswip_mdio_mask(priv, 0, BIT(port), GSWIP_MDIO_MDC_CFG0); +		u32 mdio_phy = 0; + +		if (phydev) +			mdio_phy = phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK; + +		gswip_mdio_mask(priv, GSWIP_MDIO_PHY_ADDR_MASK, mdio_phy, +				GSWIP_MDIO_PHYp(port));  	}  	return 0; @@ -675,14 +695,6 @@ static void gswip_port_disable(struct dsa_switch *ds, int port)  	if (!dsa_is_user_port(ds, port))  		return; -	if (!dsa_is_cpu_port(ds, port)) { -		gswip_mdio_mask(priv, GSWIP_MDIO_PHY_LINK_DOWN, -				GSWIP_MDIO_PHY_LINK_MASK, -				GSWIP_MDIO_PHYp(port)); -		/* Deactivate MDIO auto polling */ -		gswip_mdio_mask(priv, BIT(port), 0, GSWIP_MDIO_MDC_CFG0); -	} -  	gswip_switch_mask(priv, GSWIP_FDMA_PCTRL_EN, 0,  			  GSWIP_FDMA_PCTRLp(port));  	gswip_switch_mask(priv, GSWIP_SDMA_PCTRL_EN, 0, @@ -794,14 +806,32 @@ static int gswip_setup(struct dsa_switch *ds)  	gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP2);  	gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP3); -	/* disable PHY auto polling */ +	/* Deactivate MDIO PHY auto polling. Some PHYs as the AR8030 have an +	 * interoperability problem with this auto polling mechanism because +	 * their status registers think that the link is in a different state +	 * than it actually is. For the AR8030 it has the BMSR_ESTATEN bit set +	 * as well as ESTATUS_1000_TFULL and ESTATUS_1000_XFULL. This makes the +	 * auto polling state machine consider the link being negotiated with +	 * 1Gbit/s. Since the PHY itself is a Fast Ethernet RMII PHY this leads +	 * to the switch port being completely dead (RX and TX are both not +	 * working). +	 * Also with various other PHY / port combinations (PHY11G GPHY, PHY22F +	 * GPHY, external RGMII PEF7071/7072) any traffic would stop. Sometimes +	 * it would work fine for a few minutes to hours and then stop, on +	 * other device it would no traffic could be sent or received at all. +	 * Testing shows that when PHY auto polling is disabled these problems +	 * go away. +	 */  	gswip_mdio_w(priv, 0x0, GSWIP_MDIO_MDC_CFG0); +  	/* Configure the MDIO Clock 2.5 MHz */  	gswip_mdio_mask(priv, 0xff, 0x09, GSWIP_MDIO_MDC_CFG1); -	/* Disable the xMII link */ +	/* Disable the xMII interface and clear it's isolation bit */  	for (i = 0; i < priv->hw_info->max_ports; i++) -		gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, i); +		gswip_mii_mask_cfg(priv, +				   GSWIP_MII_CFG_EN | GSWIP_MII_CFG_ISOLATE, +				   0, i);  	/* enable special tag insertion on cpu port */  	gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_STEN, @@ -1384,12 +1414,42 @@ static int gswip_port_fdb_dump(struct dsa_switch *ds, int port,  	return 0;  } -static void gswip_phylink_validate(struct dsa_switch *ds, int port, -				   unsigned long *supported, -				   struct phylink_link_state *state) +static void gswip_phylink_set_capab(unsigned long *supported, +				    struct phylink_link_state *state)  {  	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; +	/* Allow all the expected bits */ +	phylink_set(mask, Autoneg); +	phylink_set_port_modes(mask); +	phylink_set(mask, Pause); +	phylink_set(mask, Asym_Pause); + +	/* With the exclusion of MII, Reverse MII and Reduced MII, we +	 * support Gigabit, including Half duplex +	 */ +	if (state->interface != PHY_INTERFACE_MODE_MII && +	    state->interface != PHY_INTERFACE_MODE_REVMII && +	    state->interface != PHY_INTERFACE_MODE_RMII) { +		phylink_set(mask, 1000baseT_Full); +		phylink_set(mask, 1000baseT_Half); +	} + +	phylink_set(mask, 10baseT_Half); +	phylink_set(mask, 10baseT_Full); +	phylink_set(mask, 100baseT_Half); +	phylink_set(mask, 100baseT_Full); + +	bitmap_and(supported, supported, mask, +		   __ETHTOOL_LINK_MODE_MASK_NBITS); +	bitmap_and(state->advertising, state->advertising, mask, +		   __ETHTOOL_LINK_MODE_MASK_NBITS); +} + +static void gswip_xrx200_phylink_validate(struct dsa_switch *ds, int port, +					  unsigned long *supported, +					  struct phylink_link_state *state) +{  	switch (port) {  	case 0:  	case 1: @@ -1416,38 +1476,160 @@ static void gswip_phylink_validate(struct dsa_switch *ds, int port,  		return;  	} -	/* Allow all the expected bits */ -	phylink_set(mask, Autoneg); -	phylink_set_port_modes(mask); -	phylink_set(mask, Pause); -	phylink_set(mask, Asym_Pause); +	gswip_phylink_set_capab(supported, state); -	/* With the exclusion of MII, Reverse MII and Reduced MII, we -	 * support Gigabit, including Half duplex -	 */ -	if (state->interface != PHY_INTERFACE_MODE_MII && -	    state->interface != PHY_INTERFACE_MODE_REVMII && -	    state->interface != PHY_INTERFACE_MODE_RMII) { -		phylink_set(mask, 1000baseT_Full); -		phylink_set(mask, 1000baseT_Half); +	return; + +unsupported: +	bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); +	dev_err(ds->dev, "Unsupported interface '%s' for port %d\n", +		phy_modes(state->interface), port); +} + +static void gswip_xrx300_phylink_validate(struct dsa_switch *ds, int port, +					  unsigned long *supported, +					  struct phylink_link_state *state) +{ +	switch (port) { +	case 0: +		if (!phy_interface_mode_is_rgmii(state->interface) && +		    state->interface != PHY_INTERFACE_MODE_GMII && +		    state->interface != PHY_INTERFACE_MODE_RMII) +			goto unsupported; +		break; +	case 1: +	case 2: +	case 3: +	case 4: +		if (state->interface != PHY_INTERFACE_MODE_INTERNAL) +			goto unsupported; +		break; +	case 5: +		if (!phy_interface_mode_is_rgmii(state->interface) && +		    state->interface != PHY_INTERFACE_MODE_INTERNAL && +		    state->interface != PHY_INTERFACE_MODE_RMII) +			goto unsupported; +		break; +	default: +		bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); +		dev_err(ds->dev, "Unsupported port: %i\n", port); +		return;  	} -	phylink_set(mask, 10baseT_Half); -	phylink_set(mask, 10baseT_Full); -	phylink_set(mask, 100baseT_Half); -	phylink_set(mask, 100baseT_Full); +	gswip_phylink_set_capab(supported, state); -	bitmap_and(supported, supported, mask, -		   __ETHTOOL_LINK_MODE_MASK_NBITS); -	bitmap_and(state->advertising, state->advertising, mask, -		   __ETHTOOL_LINK_MODE_MASK_NBITS);  	return;  unsupported:  	bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);  	dev_err(ds->dev, "Unsupported interface '%s' for port %d\n",  		phy_modes(state->interface), port); -	return; +} + +static void gswip_port_set_link(struct gswip_priv *priv, int port, bool link) +{ +	u32 mdio_phy; + +	if (link) +		mdio_phy = GSWIP_MDIO_PHY_LINK_UP; +	else +		mdio_phy = GSWIP_MDIO_PHY_LINK_DOWN; + +	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_LINK_MASK, mdio_phy, +			GSWIP_MDIO_PHYp(port)); +} + +static void gswip_port_set_speed(struct gswip_priv *priv, int port, int speed, +				 phy_interface_t interface) +{ +	u32 mdio_phy = 0, mii_cfg = 0, mac_ctrl_0 = 0; + +	switch (speed) { +	case SPEED_10: +		mdio_phy = GSWIP_MDIO_PHY_SPEED_M10; + +		if (interface == PHY_INTERFACE_MODE_RMII) +			mii_cfg = GSWIP_MII_CFG_RATE_M50; +		else +			mii_cfg = GSWIP_MII_CFG_RATE_M2P5; + +		mac_ctrl_0 = GSWIP_MAC_CTRL_0_GMII_MII; +		break; + +	case SPEED_100: +		mdio_phy = GSWIP_MDIO_PHY_SPEED_M100; + +		if (interface == PHY_INTERFACE_MODE_RMII) +			mii_cfg = GSWIP_MII_CFG_RATE_M50; +		else +			mii_cfg = GSWIP_MII_CFG_RATE_M25; + +		mac_ctrl_0 = GSWIP_MAC_CTRL_0_GMII_MII; +		break; + +	case SPEED_1000: +		mdio_phy = GSWIP_MDIO_PHY_SPEED_G1; + +		mii_cfg = GSWIP_MII_CFG_RATE_M125; + +		mac_ctrl_0 = GSWIP_MAC_CTRL_0_GMII_RGMII; +		break; +	} + +	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_SPEED_MASK, mdio_phy, +			GSWIP_MDIO_PHYp(port)); +	gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_RATE_MASK, mii_cfg, port); +	gswip_switch_mask(priv, GSWIP_MAC_CTRL_0_GMII_MASK, mac_ctrl_0, +			  GSWIP_MAC_CTRL_0p(port)); +} + +static void gswip_port_set_duplex(struct gswip_priv *priv, int port, int duplex) +{ +	u32 mac_ctrl_0, mdio_phy; + +	if (duplex == DUPLEX_FULL) { +		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FDUP_EN; +		mdio_phy = GSWIP_MDIO_PHY_FDUP_EN; +	} else { +		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FDUP_DIS; +		mdio_phy = GSWIP_MDIO_PHY_FDUP_DIS; +	} + +	gswip_switch_mask(priv, GSWIP_MAC_CTRL_0_FDUP_MASK, mac_ctrl_0, +			  GSWIP_MAC_CTRL_0p(port)); +	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_FDUP_MASK, mdio_phy, +			GSWIP_MDIO_PHYp(port)); +} + +static void gswip_port_set_pause(struct gswip_priv *priv, int port, +				 bool tx_pause, bool rx_pause) +{ +	u32 mac_ctrl_0, mdio_phy; + +	if (tx_pause && rx_pause) { +		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_RXTX; +		mdio_phy = GSWIP_MDIO_PHY_FCONTX_EN | +			   GSWIP_MDIO_PHY_FCONRX_EN; +	} else if (tx_pause) { +		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_TX; +		mdio_phy = GSWIP_MDIO_PHY_FCONTX_EN | +			   GSWIP_MDIO_PHY_FCONRX_DIS; +	} else if (rx_pause) { +		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_RX; +		mdio_phy = GSWIP_MDIO_PHY_FCONTX_DIS | +			   GSWIP_MDIO_PHY_FCONRX_EN; +	} else { +		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_NONE; +		mdio_phy = GSWIP_MDIO_PHY_FCONTX_DIS | +			   GSWIP_MDIO_PHY_FCONRX_DIS; +	} + +	gswip_switch_mask(priv, GSWIP_MAC_CTRL_0_FCON_MASK, +			  mac_ctrl_0, GSWIP_MAC_CTRL_0p(port)); +	gswip_mdio_mask(priv, +			GSWIP_MDIO_PHY_FCONTX_MASK | +			GSWIP_MDIO_PHY_FCONRX_MASK, +			mdio_phy, GSWIP_MDIO_PHYp(port));  }  static void gswip_phylink_mac_config(struct dsa_switch *ds, int port, @@ -1469,6 +1651,9 @@ static void gswip_phylink_mac_config(struct dsa_switch *ds, int port,  		break;  	case PHY_INTERFACE_MODE_RMII:  		miicfg |= GSWIP_MII_CFG_MODE_RMIIM; + +		/* Configure the RMII clock as output: */ +		miicfg |= GSWIP_MII_CFG_RMII_CLK;  		break;  	case PHY_INTERFACE_MODE_RGMII:  	case PHY_INTERFACE_MODE_RGMII_ID: @@ -1476,12 +1661,19 @@ static void gswip_phylink_mac_config(struct dsa_switch *ds, int port,  	case PHY_INTERFACE_MODE_RGMII_TXID:  		miicfg |= GSWIP_MII_CFG_MODE_RGMII;  		break; +	case PHY_INTERFACE_MODE_GMII: +		miicfg |= GSWIP_MII_CFG_MODE_GMII; +		break;  	default:  		dev_err(ds->dev,  			"Unsupported interface: %d\n", state->interface);  		return;  	} -	gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_MODE_MASK, miicfg, port); + +	gswip_mii_mask_cfg(priv, +			   GSWIP_MII_CFG_MODE_MASK | GSWIP_MII_CFG_RMII_CLK | +			   GSWIP_MII_CFG_RGMII_IBS | GSWIP_MII_CFG_LDCLKDIS, +			   miicfg, port);  	switch (state->interface) {  	case PHY_INTERFACE_MODE_RGMII_ID: @@ -1506,6 +1698,9 @@ static void gswip_phylink_mac_link_down(struct dsa_switch *ds, int port,  	struct gswip_priv *priv = ds->priv;  	gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, port); + +	if (!dsa_is_cpu_port(ds, port)) +		gswip_port_set_link(priv, port, false);  }  static void gswip_phylink_mac_link_up(struct dsa_switch *ds, int port, @@ -1517,6 +1712,13 @@ static void gswip_phylink_mac_link_up(struct dsa_switch *ds, int port,  {  	struct gswip_priv *priv = ds->priv; +	if (!dsa_is_cpu_port(ds, port)) { +		gswip_port_set_link(priv, port, true); +		gswip_port_set_speed(priv, port, speed, interface); +		gswip_port_set_duplex(priv, port, duplex); +		gswip_port_set_pause(priv, port, tx_pause, rx_pause); +	} +  	gswip_mii_mask_cfg(priv, 0, GSWIP_MII_CFG_EN, port);  } @@ -1588,7 +1790,7 @@ static int gswip_get_sset_count(struct dsa_switch *ds, int port, int sset)  	return ARRAY_SIZE(gswip_rmon_cnt);  } -static const struct dsa_switch_ops gswip_switch_ops = { +static const struct dsa_switch_ops gswip_xrx200_switch_ops = {  	.get_tag_protocol	= gswip_get_tag_protocol,  	.setup			= gswip_setup,  	.port_enable		= gswip_port_enable, @@ -1603,7 +1805,31 @@ static const struct dsa_switch_ops gswip_switch_ops = {  	.port_fdb_add		= gswip_port_fdb_add,  	.port_fdb_del		= gswip_port_fdb_del,  	.port_fdb_dump		= gswip_port_fdb_dump, -	.phylink_validate	= gswip_phylink_validate, +	.phylink_validate	= gswip_xrx200_phylink_validate, +	.phylink_mac_config	= gswip_phylink_mac_config, +	.phylink_mac_link_down	= gswip_phylink_mac_link_down, +	.phylink_mac_link_up	= gswip_phylink_mac_link_up, +	.get_strings		= gswip_get_strings, +	.get_ethtool_stats	= gswip_get_ethtool_stats, +	.get_sset_count		= gswip_get_sset_count, +}; + +static const struct dsa_switch_ops gswip_xrx300_switch_ops = { +	.get_tag_protocol	= gswip_get_tag_protocol, +	.setup			= gswip_setup, +	.port_enable		= gswip_port_enable, +	.port_disable		= gswip_port_disable, +	.port_bridge_join	= gswip_port_bridge_join, +	.port_bridge_leave	= gswip_port_bridge_leave, +	.port_fast_age		= gswip_port_fast_age, +	.port_vlan_filtering	= gswip_port_vlan_filtering, +	.port_vlan_add		= gswip_port_vlan_add, +	.port_vlan_del		= gswip_port_vlan_del, +	.port_stp_state_set	= gswip_port_stp_state_set, +	.port_fdb_add		= gswip_port_fdb_add, +	.port_fdb_del		= gswip_port_fdb_del, +	.port_fdb_dump		= gswip_port_fdb_dump, +	.phylink_validate	= gswip_xrx300_phylink_validate,  	.phylink_mac_config	= gswip_phylink_mac_config,  	.phylink_mac_link_down	= gswip_phylink_mac_link_down,  	.phylink_mac_link_up	= gswip_phylink_mac_link_up, @@ -1832,7 +2058,7 @@ remove_gphy:  static int gswip_probe(struct platform_device *pdev)  {  	struct gswip_priv *priv; -	struct device_node *mdio_np, *gphy_fw_np; +	struct device_node *np, *mdio_np, *gphy_fw_np;  	struct device *dev = &pdev->dev;  	int err;  	int i; @@ -1865,10 +2091,28 @@ static int gswip_probe(struct platform_device *pdev)  	priv->ds->dev = dev;  	priv->ds->num_ports = priv->hw_info->max_ports;  	priv->ds->priv = priv; -	priv->ds->ops = &gswip_switch_ops; +	priv->ds->ops = priv->hw_info->ops;  	priv->dev = dev;  	version = gswip_switch_r(priv, GSWIP_VERSION); +	np = dev->of_node; +	switch (version) { +	case GSWIP_VERSION_2_0: +	case GSWIP_VERSION_2_1: +		if (!of_device_is_compatible(np, "lantiq,xrx200-gswip")) +			return -EINVAL; +		break; +	case GSWIP_VERSION_2_2: +	case GSWIP_VERSION_2_2_ETC: +		if (!of_device_is_compatible(np, "lantiq,xrx300-gswip") && +		    !of_device_is_compatible(np, "lantiq,xrx330-gswip")) +			return -EINVAL; +		break; +	default: +		dev_err(dev, "unknown GSWIP version: 0x%x", version); +		return -ENOENT; +	} +  	/* bring up the mdio bus */  	gphy_fw_np = of_get_compatible_child(dev->of_node, "lantiq,gphy-fw");  	if (gphy_fw_np) { @@ -1946,10 +2190,19 @@ static int gswip_remove(struct platform_device *pdev)  static const struct gswip_hw_info gswip_xrx200 = {  	.max_ports = 7,  	.cpu_port = 6, +	.ops = &gswip_xrx200_switch_ops, +}; + +static const struct gswip_hw_info gswip_xrx300 = { +	.max_ports = 7, +	.cpu_port = 6, +	.ops = &gswip_xrx300_switch_ops,  };  static const struct of_device_id gswip_of_match[] = {  	{ .compatible = "lantiq,xrx200-gswip", .data = &gswip_xrx200 }, +	{ .compatible = "lantiq,xrx300-gswip", .data = &gswip_xrx300 }, +	{ .compatible = "lantiq,xrx330-gswip", .data = &gswip_xrx300 },  	{},  };  MODULE_DEVICE_TABLE(of, gswip_of_match); | 
