mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net: dsa: add Broadcom SF2 switch driver
Add support for the Broadcom Starfigther 2 switch chip using a DSA driver. This switch driver supports the following features: - configuration of the external switch port interface: MII, RevMII, RGMII and RGMII_NO_ID are supported - support for the per-port MIB counters - support for link interrupts for special ports (e.g: MoCA) - powering up/down of switch memories to conserve power when ports are unused Finally, update the compatible property for the DSA core code to match our switch top-level compatible node. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									5037d532b8
								
							
						
					
					
						commit
						246d7f773c
					
				
					 6 changed files with 1006 additions and 0 deletions
				
			
		| 
						 | 
					@ -36,4 +36,15 @@ config NET_DSA_MV88E6123_61_65
 | 
				
			||||||
	  This enables support for the Marvell 88E6123/6161/6165
 | 
						  This enables support for the Marvell 88E6123/6161/6165
 | 
				
			||||||
	  ethernet switch chips.
 | 
						  ethernet switch chips.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config NET_DSA_BCM_SF2
 | 
				
			||||||
 | 
						tristate "Broadcom Starfighter 2 Ethernet switch support"
 | 
				
			||||||
 | 
						select NET_DSA
 | 
				
			||||||
 | 
						select NET_DSA_TAG_BRCM
 | 
				
			||||||
 | 
						select FIXED_PHY if NET_DSA_BCM_SF2=y
 | 
				
			||||||
 | 
						select BCM7XXX_PHY
 | 
				
			||||||
 | 
						select MDIO_BCM_UNIMAC
 | 
				
			||||||
 | 
						---help---
 | 
				
			||||||
 | 
						  This enables support for the Broadcom Starfighter 2 Ethernet
 | 
				
			||||||
 | 
						  switch chips.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endmenu
 | 
					endmenu
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,3 +7,4 @@ endif
 | 
				
			||||||
ifdef CONFIG_NET_DSA_MV88E6131
 | 
					ifdef CONFIG_NET_DSA_MV88E6131
 | 
				
			||||||
mv88e6xxx_drv-y += mv88e6131.o
 | 
					mv88e6xxx_drv-y += mv88e6131.o
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					obj-$(CONFIG_NET_DSA_BCM_SF2)	+= bcm_sf2.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										626
									
								
								drivers/net/dsa/bcm_sf2.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										626
									
								
								drivers/net/dsa/bcm_sf2.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,626 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Broadcom Starfighter 2 DSA switch driver
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2014, Broadcom Corporation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/list.h>
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/netdevice.h>
 | 
				
			||||||
 | 
					#include <linux/interrupt.h>
 | 
				
			||||||
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
 | 
					#include <linux/of.h>
 | 
				
			||||||
 | 
					#include <linux/phy.h>
 | 
				
			||||||
 | 
					#include <linux/phy_fixed.h>
 | 
				
			||||||
 | 
					#include <linux/mii.h>
 | 
				
			||||||
 | 
					#include <linux/of.h>
 | 
				
			||||||
 | 
					#include <linux/of_irq.h>
 | 
				
			||||||
 | 
					#include <linux/of_address.h>
 | 
				
			||||||
 | 
					#include <net/dsa.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "bcm_sf2.h"
 | 
				
			||||||
 | 
					#include "bcm_sf2_regs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* String, offset, and register size in bytes if different from 4 bytes */
 | 
				
			||||||
 | 
					static const struct bcm_sf2_hw_stats bcm_sf2_mib[] = {
 | 
				
			||||||
 | 
						{ "TxOctets",		0x000, 8	},
 | 
				
			||||||
 | 
						{ "TxDropPkts",		0x020		},
 | 
				
			||||||
 | 
						{ "TxQPKTQ0",		0x030		},
 | 
				
			||||||
 | 
						{ "TxBroadcastPkts",	0x040		},
 | 
				
			||||||
 | 
						{ "TxMulticastPkts",	0x050		},
 | 
				
			||||||
 | 
						{ "TxUnicastPKts",	0x060		},
 | 
				
			||||||
 | 
						{ "TxCollisions",	0x070		},
 | 
				
			||||||
 | 
						{ "TxSingleCollision",	0x080		},
 | 
				
			||||||
 | 
						{ "TxMultipleCollision", 0x090		},
 | 
				
			||||||
 | 
						{ "TxDeferredCollision", 0x0a0		},
 | 
				
			||||||
 | 
						{ "TxLateCollision",	0x0b0		},
 | 
				
			||||||
 | 
						{ "TxExcessiveCollision", 0x0c0		},
 | 
				
			||||||
 | 
						{ "TxFrameInDisc",	0x0d0		},
 | 
				
			||||||
 | 
						{ "TxPausePkts",	0x0e0		},
 | 
				
			||||||
 | 
						{ "TxQPKTQ1",		0x0f0		},
 | 
				
			||||||
 | 
						{ "TxQPKTQ2",		0x100		},
 | 
				
			||||||
 | 
						{ "TxQPKTQ3",		0x110		},
 | 
				
			||||||
 | 
						{ "TxQPKTQ4",		0x120		},
 | 
				
			||||||
 | 
						{ "TxQPKTQ5",		0x130		},
 | 
				
			||||||
 | 
						{ "RxOctets",		0x140, 8	},
 | 
				
			||||||
 | 
						{ "RxUndersizePkts",	0x160		},
 | 
				
			||||||
 | 
						{ "RxPausePkts",	0x170		},
 | 
				
			||||||
 | 
						{ "RxPkts64Octets",	0x180		},
 | 
				
			||||||
 | 
						{ "RxPkts65to127Octets", 0x190		},
 | 
				
			||||||
 | 
						{ "RxPkts128to255Octets", 0x1a0		},
 | 
				
			||||||
 | 
						{ "RxPkts256to511Octets", 0x1b0		},
 | 
				
			||||||
 | 
						{ "RxPkts512to1023Octets", 0x1c0	},
 | 
				
			||||||
 | 
						{ "RxPkts1024toMaxPktsOctets", 0x1d0	},
 | 
				
			||||||
 | 
						{ "RxOversizePkts",	0x1e0		},
 | 
				
			||||||
 | 
						{ "RxJabbers",		0x1f0		},
 | 
				
			||||||
 | 
						{ "RxAlignmentErrors",	0x200		},
 | 
				
			||||||
 | 
						{ "RxFCSErrors",	0x210		},
 | 
				
			||||||
 | 
						{ "RxGoodOctets",	0x220, 8	},
 | 
				
			||||||
 | 
						{ "RxDropPkts",		0x240		},
 | 
				
			||||||
 | 
						{ "RxUnicastPkts",	0x250		},
 | 
				
			||||||
 | 
						{ "RxMulticastPkts",	0x260		},
 | 
				
			||||||
 | 
						{ "RxBroadcastPkts",	0x270		},
 | 
				
			||||||
 | 
						{ "RxSAChanges",	0x280		},
 | 
				
			||||||
 | 
						{ "RxFragments",	0x290		},
 | 
				
			||||||
 | 
						{ "RxJumboPkt",		0x2a0		},
 | 
				
			||||||
 | 
						{ "RxSymblErr",		0x2b0		},
 | 
				
			||||||
 | 
						{ "InRangeErrCount",	0x2c0		},
 | 
				
			||||||
 | 
						{ "OutRangeErrCount",	0x2d0		},
 | 
				
			||||||
 | 
						{ "EEELpiEvent",	0x2e0		},
 | 
				
			||||||
 | 
						{ "EEELpiDuration",	0x2f0		},
 | 
				
			||||||
 | 
						{ "RxDiscard",		0x300, 8	},
 | 
				
			||||||
 | 
						{ "TxQPKTQ6",		0x320		},
 | 
				
			||||||
 | 
						{ "TxQPKTQ7",		0x330		},
 | 
				
			||||||
 | 
						{ "TxPkts64Octets",	0x340		},
 | 
				
			||||||
 | 
						{ "TxPkts65to127Octets", 0x350		},
 | 
				
			||||||
 | 
						{ "TxPkts128to255Octets", 0x360		},
 | 
				
			||||||
 | 
						{ "TxPkts256to511Ocets", 0x370		},
 | 
				
			||||||
 | 
						{ "TxPkts512to1023Ocets", 0x380		},
 | 
				
			||||||
 | 
						{ "TxPkts1024toMaxPktOcets", 0x390	},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BCM_SF2_STATS_SIZE	ARRAY_SIZE(bcm_sf2_mib)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void bcm_sf2_sw_get_strings(struct dsa_switch *ds,
 | 
				
			||||||
 | 
									   int port, uint8_t *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < BCM_SF2_STATS_SIZE; i++)
 | 
				
			||||||
 | 
							memcpy(data + i * ETH_GSTRING_LEN,
 | 
				
			||||||
 | 
							       bcm_sf2_mib[i].string, ETH_GSTRING_LEN);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void bcm_sf2_sw_get_ethtool_stats(struct dsa_switch *ds,
 | 
				
			||||||
 | 
										 int port, uint64_t *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bcm_sf2_priv *priv = ds_to_priv(ds);
 | 
				
			||||||
 | 
						const struct bcm_sf2_hw_stats *s;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						u64 val = 0;
 | 
				
			||||||
 | 
						u32 offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&priv->stats_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Now fetch the per-port counters */
 | 
				
			||||||
 | 
						for (i = 0; i < BCM_SF2_STATS_SIZE; i++) {
 | 
				
			||||||
 | 
							s = &bcm_sf2_mib[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Do a latched 64-bit read if needed */
 | 
				
			||||||
 | 
							offset = s->reg + CORE_P_MIB_OFFSET(port);
 | 
				
			||||||
 | 
							if (s->sizeof_stat == 8)
 | 
				
			||||||
 | 
								val = core_readq(priv, offset);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								val = core_readl(priv, offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							data[i] = (u64)val;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_unlock(&priv->stats_mutex);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int bcm_sf2_sw_get_sset_count(struct dsa_switch *ds)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return BCM_SF2_STATS_SIZE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *bcm_sf2_sw_probe(struct mii_bus *bus, int sw_addr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return "Broadcom Starfighter 2";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bcm_sf2_priv *priv = ds_to_priv(ds);
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						u32 reg, val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable the port memories */
 | 
				
			||||||
 | 
						reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
 | 
				
			||||||
 | 
						reg &= ~P_TXQ_PSM_VDD(port);
 | 
				
			||||||
 | 
						core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable Broadcast, Multicast, Unicast forwarding to IMP port */
 | 
				
			||||||
 | 
						reg = core_readl(priv, CORE_IMP_CTL);
 | 
				
			||||||
 | 
						reg |= (RX_BCST_EN | RX_MCST_EN | RX_UCST_EN);
 | 
				
			||||||
 | 
						reg &= ~(RX_DIS | TX_DIS);
 | 
				
			||||||
 | 
						core_writel(priv, reg, CORE_IMP_CTL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable forwarding */
 | 
				
			||||||
 | 
						core_writel(priv, SW_FWDG_EN, CORE_SWMODE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable IMP port in dumb mode */
 | 
				
			||||||
 | 
						reg = core_readl(priv, CORE_SWITCH_CTRL);
 | 
				
			||||||
 | 
						reg |= MII_DUMB_FWDG_EN;
 | 
				
			||||||
 | 
						core_writel(priv, reg, CORE_SWITCH_CTRL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Resolve which bit controls the Broadcom tag */
 | 
				
			||||||
 | 
						switch (port) {
 | 
				
			||||||
 | 
						case 8:
 | 
				
			||||||
 | 
							val = BRCM_HDR_EN_P8;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case 7:
 | 
				
			||||||
 | 
							val = BRCM_HDR_EN_P7;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case 5:
 | 
				
			||||||
 | 
							val = BRCM_HDR_EN_P5;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							val = 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable Broadcom tags for IMP port */
 | 
				
			||||||
 | 
						reg = core_readl(priv, CORE_BRCM_HDR_CTRL);
 | 
				
			||||||
 | 
						reg |= val;
 | 
				
			||||||
 | 
						core_writel(priv, reg, CORE_BRCM_HDR_CTRL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable reception Broadcom tag for CPU TX (switch RX) to
 | 
				
			||||||
 | 
						 * allow us to tag outgoing frames
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						reg = core_readl(priv, CORE_BRCM_HDR_RX_DIS);
 | 
				
			||||||
 | 
						reg &= ~(1 << port);
 | 
				
			||||||
 | 
						core_writel(priv, reg, CORE_BRCM_HDR_RX_DIS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable transmission of Broadcom tags from the switch (CPU RX) to
 | 
				
			||||||
 | 
						 * allow delivering frames to the per-port net_devices
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						reg = core_readl(priv, CORE_BRCM_HDR_TX_DIS);
 | 
				
			||||||
 | 
						reg &= ~(1 << port);
 | 
				
			||||||
 | 
						core_writel(priv, reg, CORE_BRCM_HDR_TX_DIS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Force link status for IMP port */
 | 
				
			||||||
 | 
						reg = core_readl(priv, CORE_STS_OVERRIDE_IMP);
 | 
				
			||||||
 | 
						reg |= (MII_SW_OR | LINK_STS);
 | 
				
			||||||
 | 
						core_writel(priv, reg, CORE_STS_OVERRIDE_IMP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable the IMP Port to be in the same VLAN as the other ports
 | 
				
			||||||
 | 
						 * on a per-port basis such that we only have Port i and IMP in
 | 
				
			||||||
 | 
						 * the same VLAN.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						for (i = 0; i < priv->hw_params.num_ports; i++) {
 | 
				
			||||||
 | 
							if (!((1 << i) & ds->phys_port_mask))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
 | 
				
			||||||
 | 
							reg |= (1 << port);
 | 
				
			||||||
 | 
							core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void bcm_sf2_port_setup(struct dsa_switch *ds, int port)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bcm_sf2_priv *priv = ds_to_priv(ds);
 | 
				
			||||||
 | 
						u32 reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Clear the memory power down */
 | 
				
			||||||
 | 
						reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
 | 
				
			||||||
 | 
						reg &= ~P_TXQ_PSM_VDD(port);
 | 
				
			||||||
 | 
						core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Clear the Rx and Tx disable bits and set to no spanning tree */
 | 
				
			||||||
 | 
						core_writel(priv, 0, CORE_G_PCTL_PORT(port));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable port 7 interrupts to get notified */
 | 
				
			||||||
 | 
						if (port == 7)
 | 
				
			||||||
 | 
							intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set this port, and only this one to be in the default VLAN */
 | 
				
			||||||
 | 
						reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port));
 | 
				
			||||||
 | 
						reg &= ~PORT_VLAN_CTRL_MASK;
 | 
				
			||||||
 | 
						reg |= (1 << port);
 | 
				
			||||||
 | 
						core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(port));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void bcm_sf2_port_disable(struct dsa_switch *ds, int port)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bcm_sf2_priv *priv = ds_to_priv(ds);
 | 
				
			||||||
 | 
						u32 off, reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dsa_is_cpu_port(ds, port))
 | 
				
			||||||
 | 
							off = CORE_IMP_CTL;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							off = CORE_G_PCTL_PORT(port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = core_readl(priv, off);
 | 
				
			||||||
 | 
						reg |= RX_DIS | TX_DIS;
 | 
				
			||||||
 | 
						core_writel(priv, reg, off);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Power down the port memory */
 | 
				
			||||||
 | 
						reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
 | 
				
			||||||
 | 
						reg |= P_TXQ_PSM_VDD(port);
 | 
				
			||||||
 | 
						core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bcm_sf2_priv *priv = dev_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						priv->irq0_stat = intrl2_0_readl(priv, INTRL2_CPU_STATUS) &
 | 
				
			||||||
 | 
									~priv->irq0_mask;
 | 
				
			||||||
 | 
						intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return IRQ_HANDLED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static irqreturn_t bcm_sf2_switch_1_isr(int irq, void *dev_id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bcm_sf2_priv *priv = dev_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						priv->irq1_stat = intrl2_1_readl(priv, INTRL2_CPU_STATUS) &
 | 
				
			||||||
 | 
									~priv->irq1_mask;
 | 
				
			||||||
 | 
						intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (priv->irq1_stat & P_LINK_UP_IRQ(P7_IRQ_OFF))
 | 
				
			||||||
 | 
							priv->port_sts[7].link = 1;
 | 
				
			||||||
 | 
						if (priv->irq1_stat & P_LINK_DOWN_IRQ(P7_IRQ_OFF))
 | 
				
			||||||
 | 
							priv->port_sts[7].link = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return IRQ_HANDLED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int bcm_sf2_sw_setup(struct dsa_switch *ds)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
 | 
				
			||||||
 | 
						struct bcm_sf2_priv *priv = ds_to_priv(ds);
 | 
				
			||||||
 | 
						struct device_node *dn;
 | 
				
			||||||
 | 
						void __iomem **base;
 | 
				
			||||||
 | 
						unsigned int port;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						u32 reg, rev;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock_init(&priv->indir_lock);
 | 
				
			||||||
 | 
						mutex_init(&priv->stats_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* All the interesting properties are at the parent device_node
 | 
				
			||||||
 | 
						 * level
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						dn = ds->pd->of_node->parent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						priv->irq0 = irq_of_parse_and_map(dn, 0);
 | 
				
			||||||
 | 
						priv->irq1 = irq_of_parse_and_map(dn, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						base = &priv->core;
 | 
				
			||||||
 | 
						for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
 | 
				
			||||||
 | 
							*base = of_iomap(dn, i);
 | 
				
			||||||
 | 
							if (*base == NULL) {
 | 
				
			||||||
 | 
								pr_err("unable to find register: %s\n", reg_names[i]);
 | 
				
			||||||
 | 
								return -ENODEV;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							base++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Disable all interrupts and request them */
 | 
				
			||||||
 | 
						intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
 | 
				
			||||||
 | 
						intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
 | 
				
			||||||
 | 
						intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
 | 
				
			||||||
 | 
						intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
 | 
				
			||||||
 | 
						intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
 | 
				
			||||||
 | 
						intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = request_irq(priv->irq0, bcm_sf2_switch_0_isr, 0,
 | 
				
			||||||
 | 
								  "switch_0", priv);
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							pr_err("failed to request switch_0 IRQ\n");
 | 
				
			||||||
 | 
							goto out_unmap;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = request_irq(priv->irq1, bcm_sf2_switch_1_isr, 0,
 | 
				
			||||||
 | 
								  "switch_1", priv);
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							pr_err("failed to request switch_1 IRQ\n");
 | 
				
			||||||
 | 
							goto out_free_irq0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Reset the MIB counters */
 | 
				
			||||||
 | 
						reg = core_readl(priv, CORE_GMNCFGCFG);
 | 
				
			||||||
 | 
						reg |= RST_MIB_CNT;
 | 
				
			||||||
 | 
						core_writel(priv, reg, CORE_GMNCFGCFG);
 | 
				
			||||||
 | 
						reg &= ~RST_MIB_CNT;
 | 
				
			||||||
 | 
						core_writel(priv, reg, CORE_GMNCFGCFG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Get the maximum number of ports for this switch */
 | 
				
			||||||
 | 
						priv->hw_params.num_ports = core_readl(priv, CORE_IMP0_PRT_ID) + 1;
 | 
				
			||||||
 | 
						if (priv->hw_params.num_ports > DSA_MAX_PORTS)
 | 
				
			||||||
 | 
							priv->hw_params.num_ports = DSA_MAX_PORTS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Assume a single GPHY setup if we can't read that property */
 | 
				
			||||||
 | 
						if (of_property_read_u32(dn, "brcm,num-gphy",
 | 
				
			||||||
 | 
									 &priv->hw_params.num_gphy))
 | 
				
			||||||
 | 
							priv->hw_params.num_gphy = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Enable all valid ports and disable those unused */
 | 
				
			||||||
 | 
						for (port = 0; port < priv->hw_params.num_ports; port++) {
 | 
				
			||||||
 | 
							/* IMP port receives special treatment */
 | 
				
			||||||
 | 
							if ((1 << port) & ds->phys_port_mask)
 | 
				
			||||||
 | 
								bcm_sf2_port_setup(ds, port);
 | 
				
			||||||
 | 
							else if (dsa_is_cpu_port(ds, port))
 | 
				
			||||||
 | 
								bcm_sf2_imp_setup(ds, port);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								bcm_sf2_port_disable(ds, port);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Include the pseudo-PHY address and the broadcast PHY address to
 | 
				
			||||||
 | 
						 * divert reads towards our workaround
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						ds->phys_mii_mask |= ((1 << 30) | (1 << 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rev = reg_readl(priv, REG_SWITCH_REVISION);
 | 
				
			||||||
 | 
						priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &
 | 
				
			||||||
 | 
										SWITCH_TOP_REV_MASK;
 | 
				
			||||||
 | 
						priv->hw_params.core_rev = (rev & SF2_REV_MASK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pr_info("Starfighter 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n",
 | 
				
			||||||
 | 
							priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff,
 | 
				
			||||||
 | 
							priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff,
 | 
				
			||||||
 | 
							priv->core, priv->irq0, priv->irq1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_free_irq0:
 | 
				
			||||||
 | 
						free_irq(priv->irq0, priv);
 | 
				
			||||||
 | 
					out_unmap:
 | 
				
			||||||
 | 
						base = &priv->core;
 | 
				
			||||||
 | 
						for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
 | 
				
			||||||
 | 
							iounmap(*base);
 | 
				
			||||||
 | 
							base++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int bcm_sf2_sw_set_addr(struct dsa_switch *ds, u8 *addr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr,
 | 
				
			||||||
 | 
								       int regnum, u16 val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bcm_sf2_priv *priv = ds_to_priv(ds);
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
						u32 reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = reg_readl(priv, REG_SWITCH_CNTRL);
 | 
				
			||||||
 | 
						reg |= MDIO_MASTER_SEL;
 | 
				
			||||||
 | 
						reg_writel(priv, reg, REG_SWITCH_CNTRL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Page << 8 | offset */
 | 
				
			||||||
 | 
						reg = 0x70;
 | 
				
			||||||
 | 
						reg <<= 2;
 | 
				
			||||||
 | 
						core_writel(priv, addr, reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Page << 8 | offset */
 | 
				
			||||||
 | 
						reg = 0x80 << 8 | regnum << 1;
 | 
				
			||||||
 | 
						reg <<= 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (op)
 | 
				
			||||||
 | 
							ret = core_readl(priv, reg);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							core_writel(priv, val, reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg = reg_readl(priv, REG_SWITCH_CNTRL);
 | 
				
			||||||
 | 
						reg &= ~MDIO_MASTER_SEL;
 | 
				
			||||||
 | 
						reg_writel(priv, reg, REG_SWITCH_CNTRL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret & 0xffff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int bcm_sf2_sw_phy_read(struct dsa_switch *ds, int addr, int regnum)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Intercept reads from the MDIO broadcast address or Broadcom
 | 
				
			||||||
 | 
						 * pseudo-PHY address
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						switch (addr) {
 | 
				
			||||||
 | 
						case 0:
 | 
				
			||||||
 | 
						case 30:
 | 
				
			||||||
 | 
							return bcm_sf2_sw_indir_rw(ds, 1, addr, regnum, 0);
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return 0xffff;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int bcm_sf2_sw_phy_write(struct dsa_switch *ds, int addr, int regnum,
 | 
				
			||||||
 | 
									u16 val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* Intercept writes to the MDIO broadcast address or Broadcom
 | 
				
			||||||
 | 
						 * pseudo-PHY address
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						switch (addr) {
 | 
				
			||||||
 | 
						case 0:
 | 
				
			||||||
 | 
						case 30:
 | 
				
			||||||
 | 
							bcm_sf2_sw_indir_rw(ds, 0, addr, regnum, val);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void bcm_sf2_sw_adjust_link(struct dsa_switch *ds, int port,
 | 
				
			||||||
 | 
									   struct phy_device *phydev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bcm_sf2_priv *priv = ds_to_priv(ds);
 | 
				
			||||||
 | 
						u32 id_mode_dis = 0, port_mode;
 | 
				
			||||||
 | 
						const char *str = NULL;
 | 
				
			||||||
 | 
						u32 reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (phydev->interface) {
 | 
				
			||||||
 | 
						case PHY_INTERFACE_MODE_RGMII:
 | 
				
			||||||
 | 
							str = "RGMII (no delay)";
 | 
				
			||||||
 | 
							id_mode_dis = 1;
 | 
				
			||||||
 | 
						case PHY_INTERFACE_MODE_RGMII_TXID:
 | 
				
			||||||
 | 
							if (!str)
 | 
				
			||||||
 | 
								str = "RGMII (TX delay)";
 | 
				
			||||||
 | 
							port_mode = EXT_GPHY;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case PHY_INTERFACE_MODE_MII:
 | 
				
			||||||
 | 
							str = "MII";
 | 
				
			||||||
 | 
							port_mode = EXT_EPHY;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case PHY_INTERFACE_MODE_REVMII:
 | 
				
			||||||
 | 
							str = "Reverse MII";
 | 
				
			||||||
 | 
							port_mode = EXT_REVMII;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							goto force_link;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Clear id_mode_dis bit, and the existing port mode, but
 | 
				
			||||||
 | 
						 * make sure we enable the RGMII block for data to pass
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
 | 
				
			||||||
 | 
						reg &= ~ID_MODE_DIS;
 | 
				
			||||||
 | 
						reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT);
 | 
				
			||||||
 | 
						reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg |= port_mode | RGMII_MODE_EN;
 | 
				
			||||||
 | 
						if (id_mode_dis)
 | 
				
			||||||
 | 
							reg |= ID_MODE_DIS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (phydev->pause) {
 | 
				
			||||||
 | 
							if (phydev->asym_pause)
 | 
				
			||||||
 | 
								reg |= TX_PAUSE_EN;
 | 
				
			||||||
 | 
							reg |= RX_PAUSE_EN;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pr_info("Port %d configured for %s\n", port, str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					force_link:
 | 
				
			||||||
 | 
						/* Force link settings detected from the PHY */
 | 
				
			||||||
 | 
						reg = SW_OVERRIDE;
 | 
				
			||||||
 | 
						switch (phydev->speed) {
 | 
				
			||||||
 | 
						case SPEED_1000:
 | 
				
			||||||
 | 
							reg |= SPDSTS_1000 << SPEED_SHIFT;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SPEED_100:
 | 
				
			||||||
 | 
							reg |= SPDSTS_100 << SPEED_SHIFT;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (phydev->link)
 | 
				
			||||||
 | 
							reg |= LINK_STS;
 | 
				
			||||||
 | 
						if (phydev->duplex == DUPLEX_FULL)
 | 
				
			||||||
 | 
							reg |= DUPLX_MODE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
 | 
				
			||||||
 | 
										 struct fixed_phy_status *status)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct bcm_sf2_priv *priv = ds_to_priv(ds);
 | 
				
			||||||
 | 
						u32 link, duplex, pause, speed;
 | 
				
			||||||
 | 
						u32 reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						link = core_readl(priv, CORE_LNKSTS);
 | 
				
			||||||
 | 
						duplex = core_readl(priv, CORE_DUPSTS);
 | 
				
			||||||
 | 
						pause = core_readl(priv, CORE_PAUSESTS);
 | 
				
			||||||
 | 
						speed = core_readl(priv, CORE_SPDSTS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						speed >>= (port * SPDSTS_SHIFT);
 | 
				
			||||||
 | 
						speed &= SPDSTS_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status->link = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Port 7 is special as we do not get link status from CORE_LNKSTS,
 | 
				
			||||||
 | 
						 * which means that we need to force the link at the port override
 | 
				
			||||||
 | 
						 * level to get the data to flow. We do use what the interrupt handler
 | 
				
			||||||
 | 
						 * did determine before.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (port == 7) {
 | 
				
			||||||
 | 
							status->link = priv->port_sts[port].link;
 | 
				
			||||||
 | 
							reg = core_readl(priv, CORE_STS_OVERRIDE_GMIIP_PORT(7));
 | 
				
			||||||
 | 
							reg |= SW_OVERRIDE;
 | 
				
			||||||
 | 
							if (status->link)
 | 
				
			||||||
 | 
								reg |= LINK_STS;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								reg &= ~LINK_STS;
 | 
				
			||||||
 | 
							core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(7));
 | 
				
			||||||
 | 
							status->duplex = 1;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							status->link = !!(link & (1 << port));
 | 
				
			||||||
 | 
							status->duplex = !!(duplex & (1 << port));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (speed) {
 | 
				
			||||||
 | 
						case SPDSTS_10:
 | 
				
			||||||
 | 
							status->speed = SPEED_10;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SPDSTS_100:
 | 
				
			||||||
 | 
							status->speed = SPEED_100;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SPDSTS_1000:
 | 
				
			||||||
 | 
							status->speed = SPEED_1000;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((pause & (1 << port)) &&
 | 
				
			||||||
 | 
						    (pause & (1 << (port + PAUSESTS_TX_PAUSE_SHIFT)))) {
 | 
				
			||||||
 | 
							status->asym_pause = 1;
 | 
				
			||||||
 | 
							status->pause = 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pause & (1 << port))
 | 
				
			||||||
 | 
							status->pause = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct dsa_switch_driver bcm_sf2_switch_driver = {
 | 
				
			||||||
 | 
						.tag_protocol		= htons(ETH_P_BRCMTAG),
 | 
				
			||||||
 | 
						.priv_size		= sizeof(struct bcm_sf2_priv),
 | 
				
			||||||
 | 
						.probe			= bcm_sf2_sw_probe,
 | 
				
			||||||
 | 
						.setup			= bcm_sf2_sw_setup,
 | 
				
			||||||
 | 
						.set_addr		= bcm_sf2_sw_set_addr,
 | 
				
			||||||
 | 
						.phy_read		= bcm_sf2_sw_phy_read,
 | 
				
			||||||
 | 
						.phy_write		= bcm_sf2_sw_phy_write,
 | 
				
			||||||
 | 
						.get_strings		= bcm_sf2_sw_get_strings,
 | 
				
			||||||
 | 
						.get_ethtool_stats	= bcm_sf2_sw_get_ethtool_stats,
 | 
				
			||||||
 | 
						.get_sset_count		= bcm_sf2_sw_get_sset_count,
 | 
				
			||||||
 | 
						.adjust_link		= bcm_sf2_sw_adjust_link,
 | 
				
			||||||
 | 
						.fixed_link_update	= bcm_sf2_sw_fixed_link_update,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __init bcm_sf2_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						register_switch_driver(&bcm_sf2_switch_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					module_init(bcm_sf2_init);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void __exit bcm_sf2_exit(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unregister_switch_driver(&bcm_sf2_switch_driver);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					module_exit(bcm_sf2_exit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_AUTHOR("Broadcom Corporation");
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("Driver for Broadcom Starfighter 2 ethernet switch chip");
 | 
				
			||||||
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
 | 
					MODULE_ALIAS("platform:brcm-sf2");
 | 
				
			||||||
							
								
								
									
										140
									
								
								drivers/net/dsa/bcm_sf2.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								drivers/net/dsa/bcm_sf2.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,140 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Broadcom Starfighter2 private context
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2014, Broadcom Corporation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __BCM_SF2_H
 | 
				
			||||||
 | 
					#define __BCM_SF2_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/io.h>
 | 
				
			||||||
 | 
					#include <linux/spinlock.h>
 | 
				
			||||||
 | 
					#include <linux/mutex.h>
 | 
				
			||||||
 | 
					#include <linux/mii.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <net/dsa.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "bcm_sf2_regs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bcm_sf2_hw_params {
 | 
				
			||||||
 | 
						u16	top_rev;
 | 
				
			||||||
 | 
						u16	core_rev;
 | 
				
			||||||
 | 
						u32	num_gphy;
 | 
				
			||||||
 | 
						u8	num_acb_queue;
 | 
				
			||||||
 | 
						u8	num_rgmii;
 | 
				
			||||||
 | 
						u8	num_ports;
 | 
				
			||||||
 | 
						u8	fcb_pause_override:1;
 | 
				
			||||||
 | 
						u8	acb_packets_inflight:1;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BCM_SF2_REGS_NAME {\
 | 
				
			||||||
 | 
						"core", "reg", "intrl2_0", "intrl2_1", "fcb", "acb" \
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BCM_SF2_REGS_NUM	6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bcm_sf2_port_status {
 | 
				
			||||||
 | 
						unsigned int link;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bcm_sf2_priv {
 | 
				
			||||||
 | 
						/* Base registers, keep those in order with BCM_SF2_REGS_NAME */
 | 
				
			||||||
 | 
						void __iomem			*core;
 | 
				
			||||||
 | 
						void __iomem			*reg;
 | 
				
			||||||
 | 
						void __iomem			*intrl2_0;
 | 
				
			||||||
 | 
						void __iomem			*intrl2_1;
 | 
				
			||||||
 | 
						void __iomem			*fcb;
 | 
				
			||||||
 | 
						void __iomem			*acb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* spinlock protecting access to the indirect registers */
 | 
				
			||||||
 | 
						spinlock_t			indir_lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int				irq0;
 | 
				
			||||||
 | 
						int				irq1;
 | 
				
			||||||
 | 
						u32				irq0_stat;
 | 
				
			||||||
 | 
						u32				irq0_mask;
 | 
				
			||||||
 | 
						u32				irq1_stat;
 | 
				
			||||||
 | 
						u32				irq1_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Mutex protecting access to the MIB counters */
 | 
				
			||||||
 | 
						struct mutex			stats_mutex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct bcm_sf2_hw_params	hw_params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct bcm_sf2_port_status	port_sts[DSA_MAX_PORTS];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct bcm_sf2_hw_stats {
 | 
				
			||||||
 | 
						const char	*string;
 | 
				
			||||||
 | 
						u16		reg;
 | 
				
			||||||
 | 
						u8		sizeof_stat;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SF2_IO_MACRO(name) \
 | 
				
			||||||
 | 
					static inline u32 name##_readl(struct bcm_sf2_priv *priv, u32 off)	\
 | 
				
			||||||
 | 
					{									\
 | 
				
			||||||
 | 
						return __raw_readl(priv->name + off);				\
 | 
				
			||||||
 | 
					}									\
 | 
				
			||||||
 | 
					static inline void name##_writel(struct bcm_sf2_priv *priv,		\
 | 
				
			||||||
 | 
									  u32 val, u32 off)			\
 | 
				
			||||||
 | 
					{									\
 | 
				
			||||||
 | 
						__raw_writel(val, priv->name + off);				\
 | 
				
			||||||
 | 
					}									\
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Accesses to 64-bits register requires us to latch the hi/lo pairs
 | 
				
			||||||
 | 
					 * using the REG_DIR_DATA_{READ,WRITE} ancillary registers. The 'indir_lock'
 | 
				
			||||||
 | 
					 * spinlock is automatically grabbed and released to provide relative
 | 
				
			||||||
 | 
					 * atomiticy with latched reads/writes.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define SF2_IO64_MACRO(name) \
 | 
				
			||||||
 | 
					static inline u64 name##_readq(struct bcm_sf2_priv *priv, u32 off)	\
 | 
				
			||||||
 | 
					{									\
 | 
				
			||||||
 | 
						u32 indir, dir;							\
 | 
				
			||||||
 | 
						spin_lock(&priv->indir_lock);					\
 | 
				
			||||||
 | 
						indir = reg_readl(priv, REG_DIR_DATA_READ);			\
 | 
				
			||||||
 | 
						dir = __raw_readl(priv->name + off);				\
 | 
				
			||||||
 | 
						spin_unlock(&priv->indir_lock);					\
 | 
				
			||||||
 | 
						return (u64)indir << 32 | dir;					\
 | 
				
			||||||
 | 
					}									\
 | 
				
			||||||
 | 
					static inline void name##_writeq(struct bcm_sf2_priv *priv, u32 off,	\
 | 
				
			||||||
 | 
												u64 val)	\
 | 
				
			||||||
 | 
					{									\
 | 
				
			||||||
 | 
						spin_lock(&priv->indir_lock);					\
 | 
				
			||||||
 | 
						reg_writel(priv, upper_32_bits(val), REG_DIR_DATA_WRITE);	\
 | 
				
			||||||
 | 
						__raw_writel(lower_32_bits(val), priv->name + off);		\
 | 
				
			||||||
 | 
						spin_unlock(&priv->indir_lock);					\
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SWITCH_INTR_L2(which)						\
 | 
				
			||||||
 | 
					static inline void intrl2_##which##_mask_clear(struct bcm_sf2_priv *priv, \
 | 
				
			||||||
 | 
											u32 mask)		\
 | 
				
			||||||
 | 
					{									\
 | 
				
			||||||
 | 
						intrl2_##which##_writel(priv, mask, INTRL2_CPU_MASK_CLEAR);	\
 | 
				
			||||||
 | 
						priv->irq##which##_mask &= ~(mask);				\
 | 
				
			||||||
 | 
					}									\
 | 
				
			||||||
 | 
					static inline void intrl2_##which##_mask_set(struct bcm_sf2_priv *priv, \
 | 
				
			||||||
 | 
											u32 mask)		\
 | 
				
			||||||
 | 
					{									\
 | 
				
			||||||
 | 
						intrl2_## which##_writel(priv, mask, INTRL2_CPU_MASK_SET);	\
 | 
				
			||||||
 | 
						priv->irq##which##_mask |= (mask);				\
 | 
				
			||||||
 | 
					}									\
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SF2_IO_MACRO(core);
 | 
				
			||||||
 | 
					SF2_IO_MACRO(reg);
 | 
				
			||||||
 | 
					SF2_IO64_MACRO(core);
 | 
				
			||||||
 | 
					SF2_IO_MACRO(intrl2_0);
 | 
				
			||||||
 | 
					SF2_IO_MACRO(intrl2_1);
 | 
				
			||||||
 | 
					SF2_IO_MACRO(fcb);
 | 
				
			||||||
 | 
					SF2_IO_MACRO(acb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SWITCH_INTR_L2(0);
 | 
				
			||||||
 | 
					SWITCH_INTR_L2(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __BCM_SF2_H */
 | 
				
			||||||
							
								
								
									
										227
									
								
								drivers/net/dsa/bcm_sf2_regs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								drivers/net/dsa/bcm_sf2_regs.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,227 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Broadcom Starfighter 2 switch register defines
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2014, Broadcom Corporation
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 2 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef __BCM_SF2_REGS_H
 | 
				
			||||||
 | 
					#define __BCM_SF2_REGS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Register set relative to 'REG' */
 | 
				
			||||||
 | 
					#define REG_SWITCH_CNTRL		0x00
 | 
				
			||||||
 | 
					#define  MDIO_MASTER_SEL		(1 << 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define REG_SWITCH_STATUS		0x04
 | 
				
			||||||
 | 
					#define REG_DIR_DATA_WRITE		0x08
 | 
				
			||||||
 | 
					#define REG_DIR_DATA_READ		0x0C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define REG_SWITCH_REVISION		0x18
 | 
				
			||||||
 | 
					#define  SF2_REV_MASK			0xffff
 | 
				
			||||||
 | 
					#define  SWITCH_TOP_REV_SHIFT		16
 | 
				
			||||||
 | 
					#define  SWITCH_TOP_REV_MASK		0xffff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define REG_PHY_REVISION		0x1C
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define REG_SPHY_CNTRL			0x2C
 | 
				
			||||||
 | 
					#define  IDDQ_BIAS			(1 << 0)
 | 
				
			||||||
 | 
					#define  EXT_PWR_DOWN			(1 << 1)
 | 
				
			||||||
 | 
					#define  FORCE_DLL_EN			(1 << 2)
 | 
				
			||||||
 | 
					#define  IDDQ_GLOBAL_PWR		(1 << 3)
 | 
				
			||||||
 | 
					#define  CK25_DIS			(1 << 4)
 | 
				
			||||||
 | 
					#define  PHY_RESET			(1 << 5)
 | 
				
			||||||
 | 
					#define  PHY_PHYAD_SHIFT		8
 | 
				
			||||||
 | 
					#define  PHY_PHYAD_MASK			0x1F
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define REG_RGMII_0_BASE		0x34
 | 
				
			||||||
 | 
					#define REG_RGMII_CNTRL			0x00
 | 
				
			||||||
 | 
					#define REG_RGMII_IB_STATUS		0x04
 | 
				
			||||||
 | 
					#define REG_RGMII_RX_CLOCK_DELAY_CNTRL	0x08
 | 
				
			||||||
 | 
					#define REG_RGMII_CNTRL_SIZE		0x0C
 | 
				
			||||||
 | 
					#define REG_RGMII_CNTRL_P(x)		(REG_RGMII_0_BASE + \
 | 
				
			||||||
 | 
										((x) * REG_RGMII_CNTRL_SIZE))
 | 
				
			||||||
 | 
					/* Relative to REG_RGMII_CNTRL */
 | 
				
			||||||
 | 
					#define  RGMII_MODE_EN			(1 << 0)
 | 
				
			||||||
 | 
					#define  ID_MODE_DIS			(1 << 1)
 | 
				
			||||||
 | 
					#define  PORT_MODE_SHIFT		2
 | 
				
			||||||
 | 
					#define  INT_EPHY			(0 << PORT_MODE_SHIFT)
 | 
				
			||||||
 | 
					#define  INT_GPHY			(1 << PORT_MODE_SHIFT)
 | 
				
			||||||
 | 
					#define  EXT_EPHY			(2 << PORT_MODE_SHIFT)
 | 
				
			||||||
 | 
					#define  EXT_GPHY			(3 << PORT_MODE_SHIFT)
 | 
				
			||||||
 | 
					#define  EXT_REVMII			(4 << PORT_MODE_SHIFT)
 | 
				
			||||||
 | 
					#define  PORT_MODE_MASK			0x7
 | 
				
			||||||
 | 
					#define  RVMII_REF_SEL			(1 << 5)
 | 
				
			||||||
 | 
					#define  RX_PAUSE_EN			(1 << 6)
 | 
				
			||||||
 | 
					#define  TX_PAUSE_EN			(1 << 7)
 | 
				
			||||||
 | 
					#define  TX_CLK_STOP_EN			(1 << 8)
 | 
				
			||||||
 | 
					#define  LPI_COUNT_SHIFT		9
 | 
				
			||||||
 | 
					#define  LPI_COUNT_MASK			0x3F
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Register set relative to 'INTRL2_0' and 'INTRL2_1' */
 | 
				
			||||||
 | 
					#define INTRL2_CPU_STATUS		0x00
 | 
				
			||||||
 | 
					#define INTRL2_CPU_SET			0x04
 | 
				
			||||||
 | 
					#define INTRL2_CPU_CLEAR		0x08
 | 
				
			||||||
 | 
					#define INTRL2_CPU_MASK_STATUS		0x0c
 | 
				
			||||||
 | 
					#define INTRL2_CPU_MASK_SET		0x10
 | 
				
			||||||
 | 
					#define INTRL2_CPU_MASK_CLEAR		0x14
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Shared INTRL2_0 and INTRL2_ interrupt sources macros */
 | 
				
			||||||
 | 
					#define P_LINK_UP_IRQ(x)		(1 << (0 + (x)))
 | 
				
			||||||
 | 
					#define P_LINK_DOWN_IRQ(x)		(1 << (1 + (x)))
 | 
				
			||||||
 | 
					#define P_ENERGY_ON_IRQ(x)		(1 << (2 + (x)))
 | 
				
			||||||
 | 
					#define P_ENERGY_OFF_IRQ(x)		(1 << (3 + (x)))
 | 
				
			||||||
 | 
					#define P_GPHY_IRQ(x)			(1 << (4 + (x)))
 | 
				
			||||||
 | 
					#define P_NUM_IRQ			5
 | 
				
			||||||
 | 
					#define P_IRQ_MASK(x)			(P_LINK_UP_IRQ((x)) | \
 | 
				
			||||||
 | 
										 P_LINK_DOWN_IRQ((x)) | \
 | 
				
			||||||
 | 
										 P_ENERGY_ON_IRQ((x)) | \
 | 
				
			||||||
 | 
										 P_ENERGY_OFF_IRQ((x)) | \
 | 
				
			||||||
 | 
										 P_GPHY_IRQ((x)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* INTRL2_0 interrupt sources */
 | 
				
			||||||
 | 
					#define P0_IRQ_OFF			0
 | 
				
			||||||
 | 
					#define MEM_DOUBLE_IRQ			(1 << 5)
 | 
				
			||||||
 | 
					#define EEE_LPI_IRQ			(1 << 6)
 | 
				
			||||||
 | 
					#define P5_CPU_WAKE_IRQ			(1 << 7)
 | 
				
			||||||
 | 
					#define P8_CPU_WAKE_IRQ			(1 << 8)
 | 
				
			||||||
 | 
					#define P7_CPU_WAKE_IRQ			(1 << 9)
 | 
				
			||||||
 | 
					#define IEEE1588_IRQ			(1 << 10)
 | 
				
			||||||
 | 
					#define MDIO_ERR_IRQ			(1 << 11)
 | 
				
			||||||
 | 
					#define MDIO_DONE_IRQ			(1 << 12)
 | 
				
			||||||
 | 
					#define GISB_ERR_IRQ			(1 << 13)
 | 
				
			||||||
 | 
					#define UBUS_ERR_IRQ			(1 << 14)
 | 
				
			||||||
 | 
					#define FAILOVER_ON_IRQ			(1 << 15)
 | 
				
			||||||
 | 
					#define FAILOVER_OFF_IRQ		(1 << 16)
 | 
				
			||||||
 | 
					#define TCAM_SOFT_ERR_IRQ		(1 << 17)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* INTRL2_1 interrupt sources */
 | 
				
			||||||
 | 
					#define P7_IRQ_OFF			0
 | 
				
			||||||
 | 
					#define P_IRQ_OFF(x)			((6 - (x)) * P_NUM_IRQ)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Register set relative to 'CORE' */
 | 
				
			||||||
 | 
					#define CORE_G_PCTL_PORT0		0x00000
 | 
				
			||||||
 | 
					#define CORE_G_PCTL_PORT(x)		(CORE_G_PCTL_PORT0 + (x * 0x4))
 | 
				
			||||||
 | 
					#define CORE_IMP_CTL			0x00020
 | 
				
			||||||
 | 
					#define  RX_DIS				(1 << 0)
 | 
				
			||||||
 | 
					#define  TX_DIS				(1 << 1)
 | 
				
			||||||
 | 
					#define  RX_BCST_EN			(1 << 2)
 | 
				
			||||||
 | 
					#define  RX_MCST_EN			(1 << 3)
 | 
				
			||||||
 | 
					#define  RX_UCST_EN			(1 << 4)
 | 
				
			||||||
 | 
					#define  G_MISTP_STATE_SHIFT		5
 | 
				
			||||||
 | 
					#define  G_MISTP_NO_STP			(0 << G_MISTP_STATE_SHIFT)
 | 
				
			||||||
 | 
					#define  G_MISTP_DIS_STATE		(1 << G_MISTP_STATE_SHIFT)
 | 
				
			||||||
 | 
					#define  G_MISTP_BLOCK_STATE		(2 << G_MISTP_STATE_SHIFT)
 | 
				
			||||||
 | 
					#define  G_MISTP_LISTEN_STATE		(3 << G_MISTP_STATE_SHIFT)
 | 
				
			||||||
 | 
					#define  G_MISTP_LEARN_STATE		(4 << G_MISTP_STATE_SHIFT)
 | 
				
			||||||
 | 
					#define  G_MISTP_FWD_STATE		(5 << G_MISTP_STATE_SHIFT)
 | 
				
			||||||
 | 
					#define  G_MISTP_STATE_MASK		0x7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_SWMODE			0x0002c
 | 
				
			||||||
 | 
					#define  SW_FWDG_MODE			(1 << 0)
 | 
				
			||||||
 | 
					#define  SW_FWDG_EN			(1 << 1)
 | 
				
			||||||
 | 
					#define  RTRY_LMT_DIS			(1 << 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_STS_OVERRIDE_IMP		0x00038
 | 
				
			||||||
 | 
					#define  GMII_SPEED_UP_2G		(1 << 6)
 | 
				
			||||||
 | 
					#define  MII_SW_OR			(1 << 7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_NEW_CTRL			0x00084
 | 
				
			||||||
 | 
					#define  IP_MC				(1 << 0)
 | 
				
			||||||
 | 
					#define  OUTRANGEERR_DISCARD		(1 << 1)
 | 
				
			||||||
 | 
					#define  INRANGEERR_DISCARD		(1 << 2)
 | 
				
			||||||
 | 
					#define  CABLE_DIAG_LEN			(1 << 3)
 | 
				
			||||||
 | 
					#define  OVERRIDE_AUTO_PD_WAR		(1 << 4)
 | 
				
			||||||
 | 
					#define  EN_AUTO_PD_WAR			(1 << 5)
 | 
				
			||||||
 | 
					#define  UC_FWD_EN			(1 << 6)
 | 
				
			||||||
 | 
					#define  MC_FWD_EN			(1 << 7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_SWITCH_CTRL		0x00088
 | 
				
			||||||
 | 
					#define  MII_DUMB_FWDG_EN		(1 << 6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_SFT_LRN_CTRL		0x000f8
 | 
				
			||||||
 | 
					#define  SW_LEARN_CNTL(x)		(1 << (x))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_STS_OVERRIDE_GMIIP_PORT(x)	(0x160 + (x) * 4)
 | 
				
			||||||
 | 
					#define  LINK_STS			(1 << 0)
 | 
				
			||||||
 | 
					#define  DUPLX_MODE			(1 << 1)
 | 
				
			||||||
 | 
					#define  SPEED_SHIFT			2
 | 
				
			||||||
 | 
					#define  SPEED_MASK			0x3
 | 
				
			||||||
 | 
					#define  RXFLOW_CNTL			(1 << 4)
 | 
				
			||||||
 | 
					#define  TXFLOW_CNTL			(1 << 5)
 | 
				
			||||||
 | 
					#define  SW_OVERRIDE			(1 << 6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_WATCHDOG_CTRL		0x001e4
 | 
				
			||||||
 | 
					#define  SOFTWARE_RESET			(1 << 7)
 | 
				
			||||||
 | 
					#define  EN_CHIP_RST			(1 << 6)
 | 
				
			||||||
 | 
					#define  EN_SW_RESET			(1 << 4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_LNKSTS			0x00400
 | 
				
			||||||
 | 
					#define  LNK_STS_MASK			0x1ff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_SPDSTS			0x00410
 | 
				
			||||||
 | 
					#define  SPDSTS_10			0
 | 
				
			||||||
 | 
					#define  SPDSTS_100			1
 | 
				
			||||||
 | 
					#define  SPDSTS_1000			2
 | 
				
			||||||
 | 
					#define  SPDSTS_SHIFT			2
 | 
				
			||||||
 | 
					#define  SPDSTS_MASK			0x3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_DUPSTS			0x00420
 | 
				
			||||||
 | 
					#define  CORE_DUPSTS_MASK		0x1ff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_PAUSESTS			0x00428
 | 
				
			||||||
 | 
					#define  PAUSESTS_TX_PAUSE_SHIFT	9
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_GMNCFGCFG			0x0800
 | 
				
			||||||
 | 
					#define  RST_MIB_CNT			(1 << 0)
 | 
				
			||||||
 | 
					#define  RXBPDU_EN			(1 << 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_IMP0_PRT_ID		0x0804
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_BRCM_HDR_CTRL		0x0080c
 | 
				
			||||||
 | 
					#define  BRCM_HDR_EN_P8			(1 << 0)
 | 
				
			||||||
 | 
					#define  BRCM_HDR_EN_P5			(1 << 1)
 | 
				
			||||||
 | 
					#define  BRCM_HDR_EN_P7			(1 << 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_BRCM_HDR_CTRL2		0x0828
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_HL_PRTC_CTRL		0x0940
 | 
				
			||||||
 | 
					#define  ARP_EN				(1 << 0)
 | 
				
			||||||
 | 
					#define  RARP_EN			(1 << 1)
 | 
				
			||||||
 | 
					#define  DHCP_EN			(1 << 2)
 | 
				
			||||||
 | 
					#define  ICMPV4_EN			(1 << 3)
 | 
				
			||||||
 | 
					#define  ICMPV6_EN			(1 << 4)
 | 
				
			||||||
 | 
					#define  ICMPV6_FWD_MODE		(1 << 5)
 | 
				
			||||||
 | 
					#define  IGMP_DIP_EN			(1 << 8)
 | 
				
			||||||
 | 
					#define  IGMP_RPTLVE_EN			(1 << 9)
 | 
				
			||||||
 | 
					#define  IGMP_RTPLVE_FWD_MODE		(1 << 10)
 | 
				
			||||||
 | 
					#define  IGMP_QRY_EN			(1 << 11)
 | 
				
			||||||
 | 
					#define  IGMP_QRY_FWD_MODE		(1 << 12)
 | 
				
			||||||
 | 
					#define  IGMP_UKN_EN			(1 << 13)
 | 
				
			||||||
 | 
					#define  IGMP_UKN_FWD_MODE		(1 << 14)
 | 
				
			||||||
 | 
					#define  MLD_RPTDONE_EN			(1 << 15)
 | 
				
			||||||
 | 
					#define  MLD_RPTDONE_FWD_MODE		(1 << 16)
 | 
				
			||||||
 | 
					#define  MLD_QRY_EN			(1 << 17)
 | 
				
			||||||
 | 
					#define  MLD_QRY_FWD_MODE		(1 << 18)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_RST_MIB_CNT_EN		0x0950
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_BRCM_HDR_RX_DIS		0x0980
 | 
				
			||||||
 | 
					#define CORE_BRCM_HDR_TX_DIS		0x0988
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_MEM_PSM_VDD_CTRL		0x2380
 | 
				
			||||||
 | 
					#define  P_TXQ_PSM_VDD_SHIFT		2
 | 
				
			||||||
 | 
					#define  P_TXQ_PSM_VDD_MASK		0x3
 | 
				
			||||||
 | 
					#define  P_TXQ_PSM_VDD(x)		(P_TXQ_PSM_VDD_MASK << \
 | 
				
			||||||
 | 
										((x) * P_TXQ_PSM_VDD_SHIFT))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define	CORE_P0_MIB_OFFSET		0x8000
 | 
				
			||||||
 | 
					#define P_MIB_SIZE			0x400
 | 
				
			||||||
 | 
					#define CORE_P_MIB_OFFSET(x)		(CORE_P0_MIB_OFFSET + (x) * P_MIB_SIZE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CORE_PORT_VLAN_CTL_PORT(x)	(0xc400 + ((x) * 0x8))
 | 
				
			||||||
 | 
					#define  PORT_VLAN_CTRL_MASK		0x1ff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __BCM_SF2_REGS_H */
 | 
				
			||||||
| 
						 | 
					@ -635,6 +635,7 @@ struct packet_type dsa_pack_type __read_mostly = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct of_device_id dsa_of_match_table[] = {
 | 
					static const struct of_device_id dsa_of_match_table[] = {
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm7445-switch-v4.0" },
 | 
				
			||||||
	{ .compatible = "marvell,dsa", },
 | 
						{ .compatible = "marvell,dsa", },
 | 
				
			||||||
	{}
 | 
						{}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue