mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net: dsa: b53: Add support for Broadcom RoboSwitch
This patch adds support for Broadcom's BCM53xx switch family, also known as RoboSwitch. Some of these switches are ubiquituous, found in home routers, Wi-Fi routers, DSL and cable modem gateways and other networking related products. This drivers adds the library driver (b53_common.c) as well as a few bus glue drivers for MDIO, SPI, Switch Register Access Block (SRAB) and memory-mapped I/O into a SoC's address space (Broadcom BCM63xx/33xx). Basic operations are supported to bring the Layer 1/2 up and running, but not much more at this point, subsequent patches add the remaining features. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									409a5f27ed
								
							
						
					
					
						commit
						967dd82ffc
					
				
					 14 changed files with 3397 additions and 0 deletions
				
			
		
							
								
								
									
										88
									
								
								Documentation/devicetree/bindings/net/dsa/b53.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								Documentation/devicetree/bindings/net/dsa/b53.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,88 @@
 | 
				
			||||||
 | 
					Broadcom BCM53xx Ethernet switches
 | 
				
			||||||
 | 
					==================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Required properties:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- compatible: For external switch chips, compatible string must be exactly one
 | 
				
			||||||
 | 
					  of: "brcm,bcm5325"
 | 
				
			||||||
 | 
					      "brcm,bcm53115"
 | 
				
			||||||
 | 
					      "brcm,bcm53125"
 | 
				
			||||||
 | 
					      "brcm,bcm53128"
 | 
				
			||||||
 | 
					      "brcm,bcm5365"
 | 
				
			||||||
 | 
					      "brcm,bcm5395"
 | 
				
			||||||
 | 
					      "brcm,bcm5397"
 | 
				
			||||||
 | 
					      "brcm,bcm5398"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  For the BCM5310x SoCs with an integrated switch, must be one of:
 | 
				
			||||||
 | 
					      "brcm,bcm53010-srab"
 | 
				
			||||||
 | 
					      "brcm,bcm53011-srab"
 | 
				
			||||||
 | 
					      "brcm,bcm53012-srab"
 | 
				
			||||||
 | 
					      "brcm,bcm53018-srab"
 | 
				
			||||||
 | 
					      "brcm,bcm53019-srab" and the mandatory "brcm,bcm5301x-srab" string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  For the BCM63xx/33xx SoCs with an integrated switch, must be one of:
 | 
				
			||||||
 | 
					      "brcm,bcm3384-switch"
 | 
				
			||||||
 | 
					      "brcm,bcm6328-switch"
 | 
				
			||||||
 | 
					      "brcm,bcm6368-switch" and the mandatory "brcm,bcm63xx-switch"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional
 | 
				
			||||||
 | 
					required and optional properties.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Examples:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ethernet switch connected via MDIO to the host, CPU port wired to eth0:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						eth0: ethernet@10001000 {
 | 
				
			||||||
 | 
							compatible = "brcm,unimac";
 | 
				
			||||||
 | 
							reg = <0x10001000 0x1000>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fixed-link {
 | 
				
			||||||
 | 
								speed = <1000>;
 | 
				
			||||||
 | 
								duplex-full;
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mdio0: mdio@10000000 {
 | 
				
			||||||
 | 
							compatible = "brcm,unimac-mdio";
 | 
				
			||||||
 | 
							#address-cells = <1>;
 | 
				
			||||||
 | 
							#size-cells = <0>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch0: ethernet-switch@30 {
 | 
				
			||||||
 | 
								compatible = "brcm,bcm53125";
 | 
				
			||||||
 | 
								#address-cells = <1>;
 | 
				
			||||||
 | 
								#size-cells = <0>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ports {
 | 
				
			||||||
 | 
									port0@0 {
 | 
				
			||||||
 | 
										reg = <0>;
 | 
				
			||||||
 | 
										label = "lan1";
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									port1@1 {
 | 
				
			||||||
 | 
										reg = <1>;
 | 
				
			||||||
 | 
										label = "lan2";
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									port5@5 {
 | 
				
			||||||
 | 
										reg = <5>;
 | 
				
			||||||
 | 
										label = "cable-modem";
 | 
				
			||||||
 | 
										fixed-link {
 | 
				
			||||||
 | 
											speed = <1000>;
 | 
				
			||||||
 | 
											duplex-full;
 | 
				
			||||||
 | 
										};
 | 
				
			||||||
 | 
										phy-mode = "rgmii-txid";
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									port8@8 {
 | 
				
			||||||
 | 
										reg = <8>;
 | 
				
			||||||
 | 
										label = "cpu";
 | 
				
			||||||
 | 
										fixed-link {
 | 
				
			||||||
 | 
											speed = <1000>;
 | 
				
			||||||
 | 
											duplex-full;
 | 
				
			||||||
 | 
										};
 | 
				
			||||||
 | 
										phy-mode = "rgmii-txid";
 | 
				
			||||||
 | 
										ethernet = <ð0>;
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
| 
						 | 
					@ -2454,6 +2454,14 @@ L:	netdev@vger.kernel.org
 | 
				
			||||||
S:	Supported
 | 
					S:	Supported
 | 
				
			||||||
F:	drivers/net/ethernet/broadcom/b44.*
 | 
					F:	drivers/net/ethernet/broadcom/b44.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BROADCOM B53 ETHERNET SWITCH DRIVER
 | 
				
			||||||
 | 
					M:	Florian Fainelli <f.fainelli@gmail.com>
 | 
				
			||||||
 | 
					L:	netdev@vger.kernel.org
 | 
				
			||||||
 | 
					L:	openwrt-devel@lists.openwrt.org (subscribers-only)
 | 
				
			||||||
 | 
					S:	Supported
 | 
				
			||||||
 | 
					F:	drivers/net/dsa/b53/*
 | 
				
			||||||
 | 
					F:	include/linux/platform_data/b53.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BROADCOM GENET ETHERNET DRIVER
 | 
					BROADCOM GENET ETHERNET DRIVER
 | 
				
			||||||
M:	Florian Fainelli <f.fainelli@gmail.com>
 | 
					M:	Florian Fainelli <f.fainelli@gmail.com>
 | 
				
			||||||
L:	netdev@vger.kernel.org
 | 
					L:	netdev@vger.kernel.org
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,4 +28,6 @@ config NET_DSA_BCM_SF2
 | 
				
			||||||
	  This enables support for the Broadcom Starfighter 2 Ethernet
 | 
						  This enables support for the Broadcom Starfighter 2 Ethernet
 | 
				
			||||||
	  switch chips.
 | 
						  switch chips.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					source "drivers/net/dsa/b53/Kconfig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endmenu
 | 
					endmenu
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
 | 
					obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
 | 
				
			||||||
obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o
 | 
					obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o
 | 
				
			||||||
obj-$(CONFIG_NET_DSA_BCM_SF2)	+= bcm_sf2.o
 | 
					obj-$(CONFIG_NET_DSA_BCM_SF2)	+= bcm_sf2.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-y				+= b53/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										33
									
								
								drivers/net/dsa/b53/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								drivers/net/dsa/b53/Kconfig
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,33 @@
 | 
				
			||||||
 | 
					menuconfig B53
 | 
				
			||||||
 | 
						tristate "Broadcom BCM53xx managed switch support"
 | 
				
			||||||
 | 
						depends on NET_DSA
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  This driver adds support for Broadcom managed switch chips. It supports
 | 
				
			||||||
 | 
						  BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX
 | 
				
			||||||
 | 
						  integrated switches.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config B53_SPI_DRIVER
 | 
				
			||||||
 | 
						tristate "B53 SPI connected switch driver"
 | 
				
			||||||
 | 
						depends on B53 && SPI
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Select to enable support for registering switches configured through SPI.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config B53_MDIO_DRIVER
 | 
				
			||||||
 | 
						tristate "B53 MDIO connected switch driver"
 | 
				
			||||||
 | 
						depends on B53
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Select to enable support for registering switches configured through MDIO.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config B53_MMAP_DRIVER
 | 
				
			||||||
 | 
						tristate "B53 MMAP connected switch driver"
 | 
				
			||||||
 | 
						depends on B53 && HAS_IOMEM
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Select to enable support for memory-mapped switches like the BCM63XX
 | 
				
			||||||
 | 
						  integrated switches.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config B53_SRAB_DRIVER
 | 
				
			||||||
 | 
						tristate "B53 SRAB connected switch driver"
 | 
				
			||||||
 | 
						depends on B53 && HAS_IOMEM
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Select to enable support for memory-mapped Switch Register Access
 | 
				
			||||||
 | 
						  Bridge Registers (SRAB) like it is found on the BCM53010
 | 
				
			||||||
							
								
								
									
										6
									
								
								drivers/net/dsa/b53/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								drivers/net/dsa/b53/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					obj-$(CONFIG_B53)		+= b53_common.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-$(CONFIG_B53_SPI_DRIVER)	+= b53_spi.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_B53_MDIO_DRIVER)	+= b53_mdio.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_B53_MMAP_DRIVER)	+= b53_mmap.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_B53_SRAB_DRIVER)	+= b53_srab.o
 | 
				
			||||||
							
								
								
									
										1158
									
								
								drivers/net/dsa/b53/b53_common.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1158
									
								
								drivers/net/dsa/b53/b53_common.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										381
									
								
								drivers/net/dsa/b53/b53_mdio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										381
									
								
								drivers/net/dsa/b53/b53_mdio.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,381 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * B53 register access through MII registers
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission to use, copy, modify, and/or distribute this software for any
 | 
				
			||||||
 | 
					 * purpose with or without fee is hereby granted, provided that the above
 | 
				
			||||||
 | 
					 * copyright notice and this permission notice appear in all copies.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
				
			||||||
 | 
					 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
				
			||||||
 | 
					 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
				
			||||||
 | 
					 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
				
			||||||
 | 
					 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/phy.h>
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/delay.h>
 | 
				
			||||||
 | 
					#include <linux/brcmphy.h>
 | 
				
			||||||
 | 
					#include <linux/rtnetlink.h>
 | 
				
			||||||
 | 
					#include <net/dsa.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "b53_priv.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MII registers */
 | 
				
			||||||
 | 
					#define REG_MII_PAGE    0x10    /* MII Page register */
 | 
				
			||||||
 | 
					#define REG_MII_ADDR    0x11    /* MII Address register */
 | 
				
			||||||
 | 
					#define REG_MII_DATA0   0x18    /* MII Data register 0 */
 | 
				
			||||||
 | 
					#define REG_MII_DATA1   0x19    /* MII Data register 1 */
 | 
				
			||||||
 | 
					#define REG_MII_DATA2   0x1a    /* MII Data register 2 */
 | 
				
			||||||
 | 
					#define REG_MII_DATA3   0x1b    /* MII Data register 3 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define REG_MII_PAGE_ENABLE     BIT(0)
 | 
				
			||||||
 | 
					#define REG_MII_ADDR_WRITE      BIT(0)
 | 
				
			||||||
 | 
					#define REG_MII_ADDR_READ       BIT(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						u16 v;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						struct mii_bus *bus = dev->priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dev->current_page != page) {
 | 
				
			||||||
 | 
							/* set page number */
 | 
				
			||||||
 | 
							v = (page << 8) | REG_MII_PAGE_ENABLE;
 | 
				
			||||||
 | 
							ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
 | 
				
			||||||
 | 
										   REG_MII_PAGE, v);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
							dev->current_page = page;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* set register address */
 | 
				
			||||||
 | 
						v = (reg << 8) | op;
 | 
				
			||||||
 | 
						ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_ADDR, v);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* check if operation completed */
 | 
				
			||||||
 | 
						for (i = 0; i < 5; ++i) {
 | 
				
			||||||
 | 
							v = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
 | 
				
			||||||
 | 
										REG_MII_ADDR);
 | 
				
			||||||
 | 
							if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ)))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							usleep_range(10, 100);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN_ON(i == 5))
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mii_bus *bus = dev->priv;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
 | 
				
			||||||
 | 
									   REG_MII_DATA0) & 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mii_bus *bus = dev->priv;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_DATA0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mii_bus *bus = dev->priv;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_DATA0);
 | 
				
			||||||
 | 
						*val |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
 | 
				
			||||||
 | 
									    REG_MII_DATA1) << 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mii_bus *bus = dev->priv;
 | 
				
			||||||
 | 
						u64 temp = 0;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 2; i >= 0; i--) {
 | 
				
			||||||
 | 
							temp <<= 16;
 | 
				
			||||||
 | 
							temp |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
 | 
				
			||||||
 | 
									     REG_MII_DATA0 + i);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*val = temp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mii_bus *bus = dev->priv;
 | 
				
			||||||
 | 
						u64 temp = 0;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 3; i >= 0; i--) {
 | 
				
			||||||
 | 
							temp <<= 16;
 | 
				
			||||||
 | 
							temp |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR,
 | 
				
			||||||
 | 
										    REG_MII_DATA0 + i);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*val = temp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mii_bus *bus = dev->priv;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
 | 
				
			||||||
 | 
									   REG_MII_DATA0, value);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								    u16 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mii_bus *bus = dev->priv;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
 | 
				
			||||||
 | 
									   REG_MII_DATA0, value);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								    u32 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mii_bus *bus = dev->priv;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						u32 temp = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < 2; i++) {
 | 
				
			||||||
 | 
							int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
 | 
				
			||||||
 | 
										       REG_MII_DATA0 + i,
 | 
				
			||||||
 | 
										       temp & 0xffff);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
							temp >>= 16;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								    u64 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mii_bus *bus = dev->priv;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						u64 temp = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < 3; i++) {
 | 
				
			||||||
 | 
							int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
 | 
				
			||||||
 | 
										       REG_MII_DATA0 + i,
 | 
				
			||||||
 | 
										       temp & 0xffff);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
							temp >>= 16;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								    u64 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mii_bus *bus = dev->priv;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						u64 temp = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < 4; i++) {
 | 
				
			||||||
 | 
							int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR,
 | 
				
			||||||
 | 
										       REG_MII_DATA0 + i,
 | 
				
			||||||
 | 
										       temp & 0xffff);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
							temp >>= 16;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mdio_phy_read16(struct b53_device *dev, int addr, int reg,
 | 
				
			||||||
 | 
								       u16 *value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mii_bus *bus = dev->priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*value = mdiobus_read_nested(bus, addr, reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mdio_phy_write16(struct b53_device *dev, int addr, int reg,
 | 
				
			||||||
 | 
									u16 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mii_bus *bus = dev->bus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return mdiobus_write_nested(bus, addr, reg, value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct b53_io_ops b53_mdio_ops = {
 | 
				
			||||||
 | 
						.read8 = b53_mdio_read8,
 | 
				
			||||||
 | 
						.read16 = b53_mdio_read16,
 | 
				
			||||||
 | 
						.read32 = b53_mdio_read32,
 | 
				
			||||||
 | 
						.read48 = b53_mdio_read48,
 | 
				
			||||||
 | 
						.read64 = b53_mdio_read64,
 | 
				
			||||||
 | 
						.write8 = b53_mdio_write8,
 | 
				
			||||||
 | 
						.write16 = b53_mdio_write16,
 | 
				
			||||||
 | 
						.write32 = b53_mdio_write32,
 | 
				
			||||||
 | 
						.write48 = b53_mdio_write48,
 | 
				
			||||||
 | 
						.write64 = b53_mdio_write64,
 | 
				
			||||||
 | 
						.phy_read16 = b53_mdio_phy_read16,
 | 
				
			||||||
 | 
						.phy_write16 = b53_mdio_phy_write16,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define B53_BRCM_OUI_1	0x0143bc00
 | 
				
			||||||
 | 
					#define B53_BRCM_OUI_2	0x03625c00
 | 
				
			||||||
 | 
					#define B53_BRCM_OUI_3	0x00406000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mdio_probe(struct mdio_device *mdiodev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_device *dev;
 | 
				
			||||||
 | 
						u32 phy_id;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* allow the generic PHY driver to take over the non-management MDIO
 | 
				
			||||||
 | 
						 * addresses
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (mdiodev->addr != BRCM_PSEUDO_PHY_ADDR && mdiodev->addr != 0) {
 | 
				
			||||||
 | 
							dev_err(&mdiodev->dev, "leaving address %d to PHY\n",
 | 
				
			||||||
 | 
								mdiodev->addr);
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* read the first port's id */
 | 
				
			||||||
 | 
						phy_id = mdiobus_read(mdiodev->bus, 0, 2) << 16;
 | 
				
			||||||
 | 
						phy_id |= mdiobus_read(mdiodev->bus, 0, 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* BCM5325, BCM539x (OUI_1)
 | 
				
			||||||
 | 
						 * BCM53125, BCM53128 (OUI_2)
 | 
				
			||||||
 | 
						 * BCM5365 (OUI_3)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if ((phy_id & 0xfffffc00) != B53_BRCM_OUI_1 &&
 | 
				
			||||||
 | 
						    (phy_id & 0xfffffc00) != B53_BRCM_OUI_2 &&
 | 
				
			||||||
 | 
						    (phy_id & 0xfffffc00) != B53_BRCM_OUI_3) {
 | 
				
			||||||
 | 
							dev_err(&mdiodev->dev, "Unsupported device: 0x%08x\n", phy_id);
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev = b53_switch_alloc(&mdiodev->dev, &b53_mdio_ops, mdiodev->bus);
 | 
				
			||||||
 | 
						if (!dev)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* we don't use page 0xff, so force a page set */
 | 
				
			||||||
 | 
						dev->current_page = 0xff;
 | 
				
			||||||
 | 
						dev->bus = mdiodev->bus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev_set_drvdata(&mdiodev->dev, dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_switch_register(dev);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							dev_err(&mdiodev->dev, "failed to register switch: %i\n", ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void b53_mdio_remove(struct mdio_device *mdiodev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_device *dev = dev_get_drvdata(&mdiodev->dev);
 | 
				
			||||||
 | 
						struct dsa_switch *ds = dev->ds;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dsa_unregister_switch(ds);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct of_device_id b53_of_match[] = {
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm5325" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm53115" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm53125" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm53128" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm5365" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm5395" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm5397" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm5398" },
 | 
				
			||||||
 | 
						{ /* sentinel */ },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					MODULE_DEVICE_TABLE(of, b53_of_match);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct mdio_driver b53_mdio_driver = {
 | 
				
			||||||
 | 
						.probe	= b53_mdio_probe,
 | 
				
			||||||
 | 
						.remove	= b53_mdio_remove,
 | 
				
			||||||
 | 
						.mdiodrv.driver = {
 | 
				
			||||||
 | 
							.name = "bcm53xx",
 | 
				
			||||||
 | 
							.of_match_table = b53_of_match,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int __init b53_mdio_driver_register(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return mdio_driver_register(&b53_mdio_driver);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					module_init(b53_mdio_driver_register);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void __exit b53_mdio_driver_unregister(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						mdio_driver_unregister(&b53_mdio_driver);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					module_exit(b53_mdio_driver_unregister);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("B53 MDIO access driver");
 | 
				
			||||||
 | 
					MODULE_LICENSE("Dual BSD/GPL");
 | 
				
			||||||
							
								
								
									
										260
									
								
								drivers/net/dsa/b53/b53_mmap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								drivers/net/dsa/b53/b53_mmap.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,260 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * B53 register access through memory mapped registers
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2012-2013 Jonas Gorski <jogo@openwrt.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission to use, copy, modify, and/or distribute this software for any
 | 
				
			||||||
 | 
					 * purpose with or without fee is hereby granted, provided that the above
 | 
				
			||||||
 | 
					 * copyright notice and this permission notice appear in all copies.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
				
			||||||
 | 
					 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
				
			||||||
 | 
					 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
				
			||||||
 | 
					 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
				
			||||||
 | 
					 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/kconfig.h>
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/io.h>
 | 
				
			||||||
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
 | 
					#include <linux/platform_data/b53.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "b53_priv.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct b53_mmap_priv {
 | 
				
			||||||
 | 
						void __iomem *regs;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 __iomem *regs = dev->priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*val = readb(regs + (page << 8) + reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 __iomem *regs = dev->priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN_ON(reg % 2))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata &&
 | 
				
			||||||
 | 
						    dev->pdata->big_endian)
 | 
				
			||||||
 | 
							*val = __raw_readw(regs + (page << 8) + reg);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							*val = readw(regs + (page << 8) + reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 __iomem *regs = dev->priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN_ON(reg % 4))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata &&
 | 
				
			||||||
 | 
						    dev->pdata->big_endian)
 | 
				
			||||||
 | 
							*val = __raw_readl(regs + (page << 8) + reg);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							*val = readl(regs + (page << 8) + reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (WARN_ON(reg % 2))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (reg % 4) {
 | 
				
			||||||
 | 
							u16 lo;
 | 
				
			||||||
 | 
							u32 hi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							b53_mmap_read16(dev, page, reg, &lo);
 | 
				
			||||||
 | 
							b53_mmap_read32(dev, page, reg + 2, &hi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							*val = ((u64)hi << 16) | lo;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							u32 lo;
 | 
				
			||||||
 | 
							u16 hi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							b53_mmap_read32(dev, page, reg, &lo);
 | 
				
			||||||
 | 
							b53_mmap_read16(dev, page, reg + 4, &hi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							*val = ((u64)hi << 32) | lo;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 hi, lo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN_ON(reg % 4))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b53_mmap_read32(dev, page, reg, &lo);
 | 
				
			||||||
 | 
						b53_mmap_read32(dev, page, reg + 4, &hi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*val = ((u64)hi << 32) | lo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 __iomem *regs = dev->priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						writeb(value, regs + (page << 8) + reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								    u16 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 __iomem *regs = dev->priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN_ON(reg % 2))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata &&
 | 
				
			||||||
 | 
						    dev->pdata->big_endian)
 | 
				
			||||||
 | 
							__raw_writew(value, regs + (page << 8) + reg);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							writew(value, regs + (page << 8) + reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								    u32 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 __iomem *regs = dev->priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN_ON(reg % 4))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata &&
 | 
				
			||||||
 | 
						    dev->pdata->big_endian)
 | 
				
			||||||
 | 
							__raw_writel(value, regs + (page << 8) + reg);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							writel(value, regs + (page << 8) + reg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								    u64 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (WARN_ON(reg % 2))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (reg % 4) {
 | 
				
			||||||
 | 
							u32 hi = (u32)(value >> 16);
 | 
				
			||||||
 | 
							u16 lo = (u16)value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							b53_mmap_write16(dev, page, reg, lo);
 | 
				
			||||||
 | 
							b53_mmap_write32(dev, page, reg + 2, hi);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							u16 hi = (u16)(value >> 32);
 | 
				
			||||||
 | 
							u32 lo = (u32)value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							b53_mmap_write32(dev, page, reg, lo);
 | 
				
			||||||
 | 
							b53_mmap_write16(dev, page, reg + 4, hi);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								    u64 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 hi, lo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hi = upper_32_bits(value);
 | 
				
			||||||
 | 
						lo = lower_32_bits(value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN_ON(reg % 4))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b53_mmap_write32(dev, page, reg, lo);
 | 
				
			||||||
 | 
						b53_mmap_write32(dev, page, reg + 4, hi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct b53_io_ops b53_mmap_ops = {
 | 
				
			||||||
 | 
						.read8 = b53_mmap_read8,
 | 
				
			||||||
 | 
						.read16 = b53_mmap_read16,
 | 
				
			||||||
 | 
						.read32 = b53_mmap_read32,
 | 
				
			||||||
 | 
						.read48 = b53_mmap_read48,
 | 
				
			||||||
 | 
						.read64 = b53_mmap_read64,
 | 
				
			||||||
 | 
						.write8 = b53_mmap_write8,
 | 
				
			||||||
 | 
						.write16 = b53_mmap_write16,
 | 
				
			||||||
 | 
						.write32 = b53_mmap_write32,
 | 
				
			||||||
 | 
						.write48 = b53_mmap_write48,
 | 
				
			||||||
 | 
						.write64 = b53_mmap_write64,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mmap_probe(struct platform_device *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_platform_data *pdata = pdev->dev.platform_data;
 | 
				
			||||||
 | 
						struct b53_device *dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pdata)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs);
 | 
				
			||||||
 | 
						if (!dev)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pdata)
 | 
				
			||||||
 | 
							dev->pdata = pdata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						platform_set_drvdata(pdev, dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b53_switch_register(dev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_mmap_remove(struct platform_device *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_device *dev = platform_get_drvdata(pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dev)
 | 
				
			||||||
 | 
							b53_switch_remove(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct of_device_id b53_mmap_of_table[] = {
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm3384-switch" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm6328-switch" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm6368-switch" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm63xx-switch" },
 | 
				
			||||||
 | 
						{ /* sentinel */ },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct platform_driver b53_mmap_driver = {
 | 
				
			||||||
 | 
						.probe = b53_mmap_probe,
 | 
				
			||||||
 | 
						.remove = b53_mmap_remove,
 | 
				
			||||||
 | 
						.driver = {
 | 
				
			||||||
 | 
							.name = "b53-switch",
 | 
				
			||||||
 | 
							.of_match_table = b53_mmap_of_table,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_platform_driver(b53_mmap_driver);
 | 
				
			||||||
 | 
					MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("B53 MMAP access driver");
 | 
				
			||||||
 | 
					MODULE_LICENSE("Dual BSD/GPL");
 | 
				
			||||||
							
								
								
									
										322
									
								
								drivers/net/dsa/b53/b53_priv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								drivers/net/dsa/b53/b53_priv.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,322 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * B53 common definitions
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission to use, copy, modify, and/or distribute this software for any
 | 
				
			||||||
 | 
					 * purpose with or without fee is hereby granted, provided that the above
 | 
				
			||||||
 | 
					 * copyright notice and this permission notice appear in all copies.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
				
			||||||
 | 
					 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
				
			||||||
 | 
					 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
				
			||||||
 | 
					 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
				
			||||||
 | 
					 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __B53_PRIV_H
 | 
				
			||||||
 | 
					#define __B53_PRIV_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/mutex.h>
 | 
				
			||||||
 | 
					#include <linux/phy.h>
 | 
				
			||||||
 | 
					#include <net/dsa.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct b53_device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct b53_io_ops {
 | 
				
			||||||
 | 
						int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value);
 | 
				
			||||||
 | 
						int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value);
 | 
				
			||||||
 | 
						int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value);
 | 
				
			||||||
 | 
						int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
 | 
				
			||||||
 | 
						int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
 | 
				
			||||||
 | 
						int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value);
 | 
				
			||||||
 | 
						int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value);
 | 
				
			||||||
 | 
						int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value);
 | 
				
			||||||
 | 
						int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value);
 | 
				
			||||||
 | 
						int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value);
 | 
				
			||||||
 | 
						int (*phy_read16)(struct b53_device *dev, int addr, int reg, u16 *value);
 | 
				
			||||||
 | 
						int (*phy_write16)(struct b53_device *dev, int addr, int reg, u16 value);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						BCM5325_DEVICE_ID = 0x25,
 | 
				
			||||||
 | 
						BCM5365_DEVICE_ID = 0x65,
 | 
				
			||||||
 | 
						BCM5395_DEVICE_ID = 0x95,
 | 
				
			||||||
 | 
						BCM5397_DEVICE_ID = 0x97,
 | 
				
			||||||
 | 
						BCM5398_DEVICE_ID = 0x98,
 | 
				
			||||||
 | 
						BCM53115_DEVICE_ID = 0x53115,
 | 
				
			||||||
 | 
						BCM53125_DEVICE_ID = 0x53125,
 | 
				
			||||||
 | 
						BCM53128_DEVICE_ID = 0x53128,
 | 
				
			||||||
 | 
						BCM63XX_DEVICE_ID = 0x6300,
 | 
				
			||||||
 | 
						BCM53010_DEVICE_ID = 0x53010,
 | 
				
			||||||
 | 
						BCM53011_DEVICE_ID = 0x53011,
 | 
				
			||||||
 | 
						BCM53012_DEVICE_ID = 0x53012,
 | 
				
			||||||
 | 
						BCM53018_DEVICE_ID = 0x53018,
 | 
				
			||||||
 | 
						BCM53019_DEVICE_ID = 0x53019,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define B53_N_PORTS	9
 | 
				
			||||||
 | 
					#define B53_N_PORTS_25	6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct b53_port {
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct b53_device {
 | 
				
			||||||
 | 
						struct dsa_switch *ds;
 | 
				
			||||||
 | 
						struct b53_platform_data *pdata;
 | 
				
			||||||
 | 
						const char *name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct mutex reg_mutex;
 | 
				
			||||||
 | 
						struct mutex stats_mutex;
 | 
				
			||||||
 | 
						const struct b53_io_ops *ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* chip specific data */
 | 
				
			||||||
 | 
						u32 chip_id;
 | 
				
			||||||
 | 
						u8 core_rev;
 | 
				
			||||||
 | 
						u8 vta_regs[3];
 | 
				
			||||||
 | 
						u8 duplex_reg;
 | 
				
			||||||
 | 
						u8 jumbo_pm_reg;
 | 
				
			||||||
 | 
						u8 jumbo_size_reg;
 | 
				
			||||||
 | 
						int reset_gpio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* used ports mask */
 | 
				
			||||||
 | 
						u16 enabled_ports;
 | 
				
			||||||
 | 
						unsigned int cpu_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* connect specific data */
 | 
				
			||||||
 | 
						u8 current_page;
 | 
				
			||||||
 | 
						struct device *dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Master MDIO bus we got probed from */
 | 
				
			||||||
 | 
						struct mii_bus *bus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Slave MDIO bus we created */
 | 
				
			||||||
 | 
						struct mii_bus *slave_bus;
 | 
				
			||||||
 | 
						void *priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* run time configuration */
 | 
				
			||||||
 | 
						unsigned enable_jumbo:1;
 | 
				
			||||||
 | 
						unsigned allow_vid_4095:1;
 | 
				
			||||||
 | 
						unsigned int num_vlans;
 | 
				
			||||||
 | 
						unsigned int num_ports;
 | 
				
			||||||
 | 
						struct b53_port *ports;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define b53_for_each_port(dev, i) \
 | 
				
			||||||
 | 
						for (i = 0; i < B53_N_PORTS; i++) \
 | 
				
			||||||
 | 
							if (dev->enabled_ports & BIT(i))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int is5325(struct b53_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return dev->chip_id == BCM5325_DEVICE_ID;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int is5365(struct b53_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef CONFIG_BCM47XX
 | 
				
			||||||
 | 
						return dev->chip_id == BCM5365_DEVICE_ID;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int is5397_98(struct b53_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return dev->chip_id == BCM5397_DEVICE_ID ||
 | 
				
			||||||
 | 
							dev->chip_id == BCM5398_DEVICE_ID;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int is539x(struct b53_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return dev->chip_id == BCM5395_DEVICE_ID ||
 | 
				
			||||||
 | 
							dev->chip_id == BCM5397_DEVICE_ID ||
 | 
				
			||||||
 | 
							dev->chip_id == BCM5398_DEVICE_ID;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int is531x5(struct b53_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return dev->chip_id == BCM53115_DEVICE_ID ||
 | 
				
			||||||
 | 
							dev->chip_id == BCM53125_DEVICE_ID ||
 | 
				
			||||||
 | 
							dev->chip_id == BCM53128_DEVICE_ID;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int is63xx(struct b53_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef CONFIG_BCM63XX
 | 
				
			||||||
 | 
						return dev->chip_id == BCM63XX_DEVICE_ID;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int is5301x(struct b53_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return dev->chip_id == BCM53010_DEVICE_ID ||
 | 
				
			||||||
 | 
							dev->chip_id == BCM53011_DEVICE_ID ||
 | 
				
			||||||
 | 
							dev->chip_id == BCM53012_DEVICE_ID ||
 | 
				
			||||||
 | 
							dev->chip_id == BCM53018_DEVICE_ID ||
 | 
				
			||||||
 | 
							dev->chip_id == BCM53019_DEVICE_ID;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define B53_CPU_PORT_25	5
 | 
				
			||||||
 | 
					#define B53_CPU_PORT	8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int is_cpu_port(struct b53_device *dev, int port)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return dev->cpu_port;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops,
 | 
				
			||||||
 | 
									    void *priv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int b53_switch_detect(struct b53_device *dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int b53_switch_register(struct b53_device *dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void b53_switch_remove(struct b53_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						dsa_unregister_switch(dev->ds);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&dev->reg_mutex);
 | 
				
			||||||
 | 
						ret = dev->ops->read8(dev, page, reg, val);
 | 
				
			||||||
 | 
						mutex_unlock(&dev->reg_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&dev->reg_mutex);
 | 
				
			||||||
 | 
						ret = dev->ops->read16(dev, page, reg, val);
 | 
				
			||||||
 | 
						mutex_unlock(&dev->reg_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&dev->reg_mutex);
 | 
				
			||||||
 | 
						ret = dev->ops->read32(dev, page, reg, val);
 | 
				
			||||||
 | 
						mutex_unlock(&dev->reg_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&dev->reg_mutex);
 | 
				
			||||||
 | 
						ret = dev->ops->read48(dev, page, reg, val);
 | 
				
			||||||
 | 
						mutex_unlock(&dev->reg_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&dev->reg_mutex);
 | 
				
			||||||
 | 
						ret = dev->ops->read64(dev, page, reg, val);
 | 
				
			||||||
 | 
						mutex_unlock(&dev->reg_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&dev->reg_mutex);
 | 
				
			||||||
 | 
						ret = dev->ops->write8(dev, page, reg, value);
 | 
				
			||||||
 | 
						mutex_unlock(&dev->reg_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								      u16 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&dev->reg_mutex);
 | 
				
			||||||
 | 
						ret = dev->ops->write16(dev, page, reg, value);
 | 
				
			||||||
 | 
						mutex_unlock(&dev->reg_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								      u32 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&dev->reg_mutex);
 | 
				
			||||||
 | 
						ret = dev->ops->write32(dev, page, reg, value);
 | 
				
			||||||
 | 
						mutex_unlock(&dev->reg_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								      u64 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&dev->reg_mutex);
 | 
				
			||||||
 | 
						ret = dev->ops->write48(dev, page, reg, value);
 | 
				
			||||||
 | 
						mutex_unlock(&dev->reg_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								       u64 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&dev->reg_mutex);
 | 
				
			||||||
 | 
						ret = dev->ops->write64(dev, page, reg, value);
 | 
				
			||||||
 | 
						mutex_unlock(&dev->reg_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_BCM47XX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/version.h>
 | 
				
			||||||
 | 
					#include <linux/bcm47xx_nvram.h>
 | 
				
			||||||
 | 
					#include <bcm47xx_board.h>
 | 
				
			||||||
 | 
					static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						enum bcm47xx_board board = bcm47xx_board_get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (board) {
 | 
				
			||||||
 | 
						case BCM47XX_BOARD_LINKSYS_WRT300NV11:
 | 
				
			||||||
 | 
						case BCM47XX_BOARD_LINKSYS_WRT310NV1:
 | 
				
			||||||
 | 
							return 8;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return bcm47xx_nvram_gpio_pin("robo_reset");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return -ENOENT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										358
									
								
								drivers/net/dsa/b53/b53_regs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										358
									
								
								drivers/net/dsa/b53/b53_regs.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,358 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * B53 register definitions
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2004 Broadcom Corporation
 | 
				
			||||||
 | 
					 * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission to use, copy, modify, and/or distribute this software for any
 | 
				
			||||||
 | 
					 * purpose with or without fee is hereby granted, provided that the above
 | 
				
			||||||
 | 
					 * copyright notice and this permission notice appear in all copies.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
				
			||||||
 | 
					 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
				
			||||||
 | 
					 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
				
			||||||
 | 
					 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
				
			||||||
 | 
					 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __B53_REGS_H
 | 
				
			||||||
 | 
					#define __B53_REGS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Management Port (SMP) Page offsets */
 | 
				
			||||||
 | 
					#define B53_CTRL_PAGE			0x00 /* Control */
 | 
				
			||||||
 | 
					#define B53_STAT_PAGE			0x01 /* Status */
 | 
				
			||||||
 | 
					#define B53_MGMT_PAGE			0x02 /* Management Mode */
 | 
				
			||||||
 | 
					#define B53_MIB_AC_PAGE			0x03 /* MIB Autocast */
 | 
				
			||||||
 | 
					#define B53_ARLCTRL_PAGE		0x04 /* ARL Control */
 | 
				
			||||||
 | 
					#define B53_ARLIO_PAGE			0x05 /* ARL Access */
 | 
				
			||||||
 | 
					#define B53_FRAMEBUF_PAGE		0x06 /* Management frame access */
 | 
				
			||||||
 | 
					#define B53_MEM_ACCESS_PAGE		0x08 /* Memory access */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* PHY Registers */
 | 
				
			||||||
 | 
					#define B53_PORT_MII_PAGE(i)		(0x10 + (i)) /* Port i MII Registers */
 | 
				
			||||||
 | 
					#define B53_IM_PORT_PAGE		0x18 /* Inverse MII Port (to EMAC) */
 | 
				
			||||||
 | 
					#define B53_ALL_PORT_PAGE		0x19 /* All ports MII (broadcast) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MIB registers */
 | 
				
			||||||
 | 
					#define B53_MIB_PAGE(i)			(0x20 + (i))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Quality of Service (QoS) Registers */
 | 
				
			||||||
 | 
					#define B53_QOS_PAGE			0x30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Port VLAN Page */
 | 
				
			||||||
 | 
					#define B53_PVLAN_PAGE			0x31
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLAN Registers */
 | 
				
			||||||
 | 
					#define B53_VLAN_PAGE			0x34
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Jumbo Frame Registers */
 | 
				
			||||||
 | 
					#define B53_JUMBO_PAGE			0x40
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CFP Configuration Registers Page */
 | 
				
			||||||
 | 
					#define B53_CFP_PAGE			0xa1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*************************************************************************
 | 
				
			||||||
 | 
					 * Control Page registers
 | 
				
			||||||
 | 
					 *************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Port Control Register (8 bit) */
 | 
				
			||||||
 | 
					#define B53_PORT_CTRL(i)		(0x00 + (i))
 | 
				
			||||||
 | 
					#define   PORT_CTRL_RX_DISABLE		BIT(0)
 | 
				
			||||||
 | 
					#define   PORT_CTRL_TX_DISABLE		BIT(1)
 | 
				
			||||||
 | 
					#define   PORT_CTRL_RX_BCST_EN		BIT(2) /* Broadcast RX (P8 only) */
 | 
				
			||||||
 | 
					#define   PORT_CTRL_RX_MCST_EN		BIT(3) /* Multicast RX (P8 only) */
 | 
				
			||||||
 | 
					#define   PORT_CTRL_RX_UCST_EN		BIT(4) /* Unicast RX (P8 only) */
 | 
				
			||||||
 | 
					#define	  PORT_CTRL_STP_STATE_S		5
 | 
				
			||||||
 | 
					#define   PORT_CTRL_STP_STATE_MASK	(0x7 << PORT_CTRL_STP_STATE_S)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* SMP Control Register (8 bit) */
 | 
				
			||||||
 | 
					#define B53_SMP_CTRL			0x0a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Switch Mode Control Register (8 bit) */
 | 
				
			||||||
 | 
					#define B53_SWITCH_MODE			0x0b
 | 
				
			||||||
 | 
					#define   SM_SW_FWD_MODE		BIT(0)	/* 1 = Managed Mode */
 | 
				
			||||||
 | 
					#define   SM_SW_FWD_EN			BIT(1)	/* Forwarding Enable */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* IMP Port state override register (8 bit) */
 | 
				
			||||||
 | 
					#define B53_PORT_OVERRIDE_CTRL		0x0e
 | 
				
			||||||
 | 
					#define   PORT_OVERRIDE_LINK		BIT(0)
 | 
				
			||||||
 | 
					#define   PORT_OVERRIDE_FULL_DUPLEX	BIT(1) /* 0 = Half Duplex */
 | 
				
			||||||
 | 
					#define   PORT_OVERRIDE_SPEED_S		2
 | 
				
			||||||
 | 
					#define   PORT_OVERRIDE_SPEED_10M	(0 << PORT_OVERRIDE_SPEED_S)
 | 
				
			||||||
 | 
					#define   PORT_OVERRIDE_SPEED_100M	(1 << PORT_OVERRIDE_SPEED_S)
 | 
				
			||||||
 | 
					#define   PORT_OVERRIDE_SPEED_1000M	(2 << PORT_OVERRIDE_SPEED_S)
 | 
				
			||||||
 | 
					#define   PORT_OVERRIDE_RV_MII_25	BIT(4) /* BCM5325 only */
 | 
				
			||||||
 | 
					#define   PORT_OVERRIDE_RX_FLOW		BIT(4)
 | 
				
			||||||
 | 
					#define   PORT_OVERRIDE_TX_FLOW		BIT(5)
 | 
				
			||||||
 | 
					#define   PORT_OVERRIDE_SPEED_2000M	BIT(6) /* BCM5301X only, requires setting 1000M */
 | 
				
			||||||
 | 
					#define   PORT_OVERRIDE_EN		BIT(7) /* Use the register contents */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Power-down mode control */
 | 
				
			||||||
 | 
					#define B53_PD_MODE_CTRL_25		0x0f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* IP Multicast control (8 bit) */
 | 
				
			||||||
 | 
					#define B53_IP_MULTICAST_CTRL		0x21
 | 
				
			||||||
 | 
					#define  B53_IPMC_FWD_EN		BIT(1)
 | 
				
			||||||
 | 
					#define  B53_UC_FWD_EN			BIT(6)
 | 
				
			||||||
 | 
					#define  B53_MC_FWD_EN			BIT(7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* (16 bit) */
 | 
				
			||||||
 | 
					#define B53_UC_FLOOD_MASK		0x32
 | 
				
			||||||
 | 
					#define B53_MC_FLOOD_MASK		0x34
 | 
				
			||||||
 | 
					#define B53_IPMC_FLOOD_MASK		0x36
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Override Ports 0-7 State on devices with xMII interfaces (8 bit)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * For port 8 still use B53_PORT_OVERRIDE_CTRL
 | 
				
			||||||
 | 
					 * Please note that not all ports are available on every hardware, e.g. BCM5301X
 | 
				
			||||||
 | 
					 * don't include overriding port 6, BCM63xx also have some limitations.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define B53_GMII_PORT_OVERRIDE_CTRL(i)	(0x58 + (i))
 | 
				
			||||||
 | 
					#define   GMII_PO_LINK			BIT(0)
 | 
				
			||||||
 | 
					#define   GMII_PO_FULL_DUPLEX		BIT(1) /* 0 = Half Duplex */
 | 
				
			||||||
 | 
					#define   GMII_PO_SPEED_S		2
 | 
				
			||||||
 | 
					#define   GMII_PO_SPEED_10M		(0 << GMII_PO_SPEED_S)
 | 
				
			||||||
 | 
					#define   GMII_PO_SPEED_100M		(1 << GMII_PO_SPEED_S)
 | 
				
			||||||
 | 
					#define   GMII_PO_SPEED_1000M		(2 << GMII_PO_SPEED_S)
 | 
				
			||||||
 | 
					#define   GMII_PO_RX_FLOW		BIT(4)
 | 
				
			||||||
 | 
					#define   GMII_PO_TX_FLOW		BIT(5)
 | 
				
			||||||
 | 
					#define   GMII_PO_EN			BIT(6) /* Use the register contents */
 | 
				
			||||||
 | 
					#define   GMII_PO_SPEED_2000M		BIT(7) /* BCM5301X only, requires setting 1000M */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define B53_RGMII_CTRL_IMP		0x60
 | 
				
			||||||
 | 
					#define   RGMII_CTRL_ENABLE_GMII	BIT(7)
 | 
				
			||||||
 | 
					#define   RGMII_CTRL_TIMING_SEL		BIT(2)
 | 
				
			||||||
 | 
					#define   RGMII_CTRL_DLL_RXC		BIT(1)
 | 
				
			||||||
 | 
					#define   RGMII_CTRL_DLL_TXC		BIT(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define B53_RGMII_CTRL_P(i)		(B53_RGMII_CTRL_IMP + (i))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Software reset register (8 bit) */
 | 
				
			||||||
 | 
					#define B53_SOFTRESET			0x79
 | 
				
			||||||
 | 
					#define   SW_RST			BIT(7)
 | 
				
			||||||
 | 
					#define   EN_SW_RST			BIT(4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Fast Aging Control register (8 bit) */
 | 
				
			||||||
 | 
					#define B53_FAST_AGE_CTRL		0x88
 | 
				
			||||||
 | 
					#define   FAST_AGE_STATIC		BIT(0)
 | 
				
			||||||
 | 
					#define   FAST_AGE_DYNAMIC		BIT(1)
 | 
				
			||||||
 | 
					#define   FAST_AGE_PORT			BIT(2)
 | 
				
			||||||
 | 
					#define   FAST_AGE_VLAN			BIT(3)
 | 
				
			||||||
 | 
					#define   FAST_AGE_STP			BIT(4)
 | 
				
			||||||
 | 
					#define   FAST_AGE_MC			BIT(5)
 | 
				
			||||||
 | 
					#define   FAST_AGE_DONE			BIT(7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*************************************************************************
 | 
				
			||||||
 | 
					 * Status Page registers
 | 
				
			||||||
 | 
					 *************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Link Status Summary Register (16bit) */
 | 
				
			||||||
 | 
					#define B53_LINK_STAT			0x00
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Link Status Change Register (16 bit) */
 | 
				
			||||||
 | 
					#define B53_LINK_STAT_CHANGE		0x02
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */
 | 
				
			||||||
 | 
					#define B53_SPEED_STAT			0x04
 | 
				
			||||||
 | 
					#define  SPEED_PORT_FE(reg, port)	(((reg) >> (port)) & 1)
 | 
				
			||||||
 | 
					#define  SPEED_PORT_GE(reg, port)	(((reg) >> 2 * (port)) & 3)
 | 
				
			||||||
 | 
					#define  SPEED_STAT_10M			0
 | 
				
			||||||
 | 
					#define  SPEED_STAT_100M		1
 | 
				
			||||||
 | 
					#define  SPEED_STAT_1000M		2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Duplex Status Summary (16 bit) */
 | 
				
			||||||
 | 
					#define B53_DUPLEX_STAT_FE		0x06
 | 
				
			||||||
 | 
					#define B53_DUPLEX_STAT_GE		0x08
 | 
				
			||||||
 | 
					#define B53_DUPLEX_STAT_63XX		0x0c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Revision ID register for BCM5325 */
 | 
				
			||||||
 | 
					#define B53_REV_ID_25			0x50
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Strap Value (48 bit) */
 | 
				
			||||||
 | 
					#define B53_STRAP_VALUE			0x70
 | 
				
			||||||
 | 
					#define   SV_GMII_CTRL_115		BIT(27)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*************************************************************************
 | 
				
			||||||
 | 
					 * Management Mode Page Registers
 | 
				
			||||||
 | 
					 *************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Global Management Config Register (8 bit) */
 | 
				
			||||||
 | 
					#define B53_GLOBAL_CONFIG		0x00
 | 
				
			||||||
 | 
					#define   GC_RESET_MIB			0x01
 | 
				
			||||||
 | 
					#define   GC_RX_BPDU_EN			0x02
 | 
				
			||||||
 | 
					#define   GC_MIB_AC_HDR_EN		0x10
 | 
				
			||||||
 | 
					#define   GC_MIB_AC_EN			0x20
 | 
				
			||||||
 | 
					#define   GC_FRM_MGMT_PORT_M		0xC0
 | 
				
			||||||
 | 
					#define   GC_FRM_MGMT_PORT_04		0x00
 | 
				
			||||||
 | 
					#define   GC_FRM_MGMT_PORT_MII		0x80
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Broadcom Header control register (8 bit) */
 | 
				
			||||||
 | 
					#define B53_BRCM_HDR			0x03
 | 
				
			||||||
 | 
					#define   BRCM_HDR_P8_EN		BIT(0) /* Enable tagging on port 8 */
 | 
				
			||||||
 | 
					#define   BRCM_HDR_P5_EN		BIT(1) /* Enable tagging on port 5 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Device ID register (8 or 32 bit) */
 | 
				
			||||||
 | 
					#define B53_DEVICE_ID			0x30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Revision ID register (8 bit) */
 | 
				
			||||||
 | 
					#define B53_REV_ID			0x40
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*************************************************************************
 | 
				
			||||||
 | 
					 * ARL Access Page Registers
 | 
				
			||||||
 | 
					 *************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLAN Table Access Register (8 bit) */
 | 
				
			||||||
 | 
					#define B53_VT_ACCESS			0x80
 | 
				
			||||||
 | 
					#define B53_VT_ACCESS_9798		0x60 /* for BCM5397/BCM5398 */
 | 
				
			||||||
 | 
					#define B53_VT_ACCESS_63XX		0x60 /* for BCM6328/62/68 */
 | 
				
			||||||
 | 
					#define   VTA_CMD_WRITE			0
 | 
				
			||||||
 | 
					#define   VTA_CMD_READ			1
 | 
				
			||||||
 | 
					#define   VTA_CMD_CLEAR			2
 | 
				
			||||||
 | 
					#define   VTA_START_CMD			BIT(7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLAN Table Index Register (16 bit) */
 | 
				
			||||||
 | 
					#define B53_VT_INDEX			0x81
 | 
				
			||||||
 | 
					#define B53_VT_INDEX_9798		0x61
 | 
				
			||||||
 | 
					#define B53_VT_INDEX_63XX		0x62
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLAN Table Entry Register (32 bit) */
 | 
				
			||||||
 | 
					#define B53_VT_ENTRY			0x83
 | 
				
			||||||
 | 
					#define B53_VT_ENTRY_9798		0x63
 | 
				
			||||||
 | 
					#define B53_VT_ENTRY_63XX		0x64
 | 
				
			||||||
 | 
					#define   VTE_MEMBERS			0x1ff
 | 
				
			||||||
 | 
					#define   VTE_UNTAG_S			9
 | 
				
			||||||
 | 
					#define   VTE_UNTAG			(0x1ff << 9)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*************************************************************************
 | 
				
			||||||
 | 
					 * Port VLAN Registers
 | 
				
			||||||
 | 
					 *************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */
 | 
				
			||||||
 | 
					#define B53_PVLAN_PORT_MASK(i)		((i) * 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*************************************************************************
 | 
				
			||||||
 | 
					 * 802.1Q Page Registers
 | 
				
			||||||
 | 
					 *************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Global QoS Control (8 bit) */
 | 
				
			||||||
 | 
					#define B53_QOS_GLOBAL_CTL		0x00
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Enable 802.1Q for individual Ports (16 bit) */
 | 
				
			||||||
 | 
					#define B53_802_1P_EN			0x04
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*************************************************************************
 | 
				
			||||||
 | 
					 * VLAN Page Registers
 | 
				
			||||||
 | 
					 *************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLAN Control 0 (8 bit) */
 | 
				
			||||||
 | 
					#define B53_VLAN_CTRL0			0x00
 | 
				
			||||||
 | 
					#define   VC0_8021PF_CTRL_MASK		0x3
 | 
				
			||||||
 | 
					#define   VC0_8021PF_CTRL_NONE		0x0
 | 
				
			||||||
 | 
					#define   VC0_8021PF_CTRL_CHANGE_PRI	0x1
 | 
				
			||||||
 | 
					#define   VC0_8021PF_CTRL_CHANGE_VID	0x2
 | 
				
			||||||
 | 
					#define   VC0_8021PF_CTRL_CHANGE_BOTH	0x3
 | 
				
			||||||
 | 
					#define   VC0_8021QF_CTRL_MASK		0xc
 | 
				
			||||||
 | 
					#define   VC0_8021QF_CTRL_CHANGE_PRI	0x1
 | 
				
			||||||
 | 
					#define   VC0_8021QF_CTRL_CHANGE_VID	0x2
 | 
				
			||||||
 | 
					#define   VC0_8021QF_CTRL_CHANGE_BOTH	0x3
 | 
				
			||||||
 | 
					#define   VC0_RESERVED_1		BIT(1)
 | 
				
			||||||
 | 
					#define   VC0_DROP_VID_MISS		BIT(4)
 | 
				
			||||||
 | 
					#define   VC0_VID_HASH_VID		BIT(5)
 | 
				
			||||||
 | 
					#define   VC0_VID_CHK_EN		BIT(6)	/* Use VID,DA or VID,SA */
 | 
				
			||||||
 | 
					#define   VC0_VLAN_EN			BIT(7)	/* 802.1Q VLAN Enabled */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLAN Control 1 (8 bit) */
 | 
				
			||||||
 | 
					#define B53_VLAN_CTRL1			0x01
 | 
				
			||||||
 | 
					#define   VC1_RX_MCST_TAG_EN		BIT(1)
 | 
				
			||||||
 | 
					#define   VC1_RX_MCST_FWD_EN		BIT(2)
 | 
				
			||||||
 | 
					#define   VC1_RX_MCST_UNTAG_EN		BIT(3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLAN Control 2 (8 bit) */
 | 
				
			||||||
 | 
					#define B53_VLAN_CTRL2			0x02
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */
 | 
				
			||||||
 | 
					#define B53_VLAN_CTRL3			0x03
 | 
				
			||||||
 | 
					#define B53_VLAN_CTRL3_63XX		0x04
 | 
				
			||||||
 | 
					#define   VC3_MAXSIZE_1532		BIT(6) /* 5325 only */
 | 
				
			||||||
 | 
					#define   VC3_HIGH_8BIT_EN		BIT(7) /* 5325 only */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLAN Control 4 (8 bit) */
 | 
				
			||||||
 | 
					#define B53_VLAN_CTRL4			0x05
 | 
				
			||||||
 | 
					#define B53_VLAN_CTRL4_25		0x04
 | 
				
			||||||
 | 
					#define B53_VLAN_CTRL4_63XX		0x06
 | 
				
			||||||
 | 
					#define   VC4_ING_VID_CHECK_S		6
 | 
				
			||||||
 | 
					#define   VC4_ING_VID_CHECK_MASK	(0x3 << VC4_ING_VID_CHECK_S)
 | 
				
			||||||
 | 
					#define   VC4_ING_VID_VIO_FWD		0 /* forward, but do not learn */
 | 
				
			||||||
 | 
					#define   VC4_ING_VID_VIO_DROP		1 /* drop VID violations */
 | 
				
			||||||
 | 
					#define   VC4_NO_ING_VID_CHK		2 /* do not check */
 | 
				
			||||||
 | 
					#define   VC4_ING_VID_VIO_TO_IMP	3 /* redirect to MII port */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLAN Control 5 (8 bit) */
 | 
				
			||||||
 | 
					#define B53_VLAN_CTRL5			0x06
 | 
				
			||||||
 | 
					#define B53_VLAN_CTRL5_25		0x05
 | 
				
			||||||
 | 
					#define B53_VLAN_CTRL5_63XX		0x07
 | 
				
			||||||
 | 
					#define   VC5_VID_FFF_EN		BIT(2)
 | 
				
			||||||
 | 
					#define   VC5_DROP_VTABLE_MISS		BIT(3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLAN Control 6 (8 bit) */
 | 
				
			||||||
 | 
					#define B53_VLAN_CTRL6			0x07
 | 
				
			||||||
 | 
					#define B53_VLAN_CTRL6_63XX		0x08
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLAN Table Access Register (16 bit) */
 | 
				
			||||||
 | 
					#define B53_VLAN_TABLE_ACCESS_25	0x06	/* BCM5325E/5350 */
 | 
				
			||||||
 | 
					#define B53_VLAN_TABLE_ACCESS_65	0x08	/* BCM5365 */
 | 
				
			||||||
 | 
					#define   VTA_VID_LOW_MASK_25		0xf
 | 
				
			||||||
 | 
					#define   VTA_VID_LOW_MASK_65		0xff
 | 
				
			||||||
 | 
					#define   VTA_VID_HIGH_S_25		4
 | 
				
			||||||
 | 
					#define   VTA_VID_HIGH_S_65		8
 | 
				
			||||||
 | 
					#define   VTA_VID_HIGH_MASK_25		(0xff << VTA_VID_HIGH_S_25E)
 | 
				
			||||||
 | 
					#define   VTA_VID_HIGH_MASK_65		(0xf << VTA_VID_HIGH_S_65)
 | 
				
			||||||
 | 
					#define   VTA_RW_STATE			BIT(12)
 | 
				
			||||||
 | 
					#define   VTA_RW_STATE_RD		0
 | 
				
			||||||
 | 
					#define   VTA_RW_STATE_WR		BIT(12)
 | 
				
			||||||
 | 
					#define   VTA_RW_OP_EN			BIT(13)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLAN Read/Write Registers for (16/32 bit) */
 | 
				
			||||||
 | 
					#define B53_VLAN_WRITE_25		0x08
 | 
				
			||||||
 | 
					#define B53_VLAN_WRITE_65		0x0a
 | 
				
			||||||
 | 
					#define B53_VLAN_READ			0x0c
 | 
				
			||||||
 | 
					#define   VA_MEMBER_MASK		0x3f
 | 
				
			||||||
 | 
					#define   VA_UNTAG_S_25			6
 | 
				
			||||||
 | 
					#define   VA_UNTAG_MASK_25		0x3f
 | 
				
			||||||
 | 
					#define   VA_UNTAG_S_65			7
 | 
				
			||||||
 | 
					#define   VA_UNTAG_MASK_65		0x1f
 | 
				
			||||||
 | 
					#define   VA_VID_HIGH_S			12
 | 
				
			||||||
 | 
					#define   VA_VID_HIGH_MASK		(0xffff << VA_VID_HIGH_S)
 | 
				
			||||||
 | 
					#define   VA_VALID_25			BIT(20)
 | 
				
			||||||
 | 
					#define   VA_VALID_25_R4		BIT(24)
 | 
				
			||||||
 | 
					#define   VA_VALID_65			BIT(14)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* VLAN Port Default Tag (16 bit) */
 | 
				
			||||||
 | 
					#define B53_VLAN_PORT_DEF_TAG(i)	(0x10 + 2 * (i))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*************************************************************************
 | 
				
			||||||
 | 
					 * Jumbo Frame Page Registers
 | 
				
			||||||
 | 
					 *************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */
 | 
				
			||||||
 | 
					#define B53_JUMBO_PORT_MASK		0x01
 | 
				
			||||||
 | 
					#define B53_JUMBO_PORT_MASK_63XX	0x04
 | 
				
			||||||
 | 
					#define   JPM_10_100_JUMBO_EN		BIT(24) /* GigE always enabled */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Good Frame Max Size without 802.1Q TAG (16 bit) */
 | 
				
			||||||
 | 
					#define B53_JUMBO_MAX_SIZE		0x05
 | 
				
			||||||
 | 
					#define B53_JUMBO_MAX_SIZE_63XX		0x08
 | 
				
			||||||
 | 
					#define   JMS_MIN_SIZE			1518
 | 
				
			||||||
 | 
					#define   JMS_MAX_SIZE			9724
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*************************************************************************
 | 
				
			||||||
 | 
					 * CFP Configuration Page Registers
 | 
				
			||||||
 | 
					 *************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* CFP Control Register with ports map (8 bit) */
 | 
				
			||||||
 | 
					#define B53_CFP_CTRL			0x00
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* !__B53_REGS_H */
 | 
				
			||||||
							
								
								
									
										331
									
								
								drivers/net/dsa/b53/b53_spi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										331
									
								
								drivers/net/dsa/b53/b53_spi.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,331 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * B53 register access through SPI
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission to use, copy, modify, and/or distribute this software for any
 | 
				
			||||||
 | 
					 * purpose with or without fee is hereby granted, provided that the above
 | 
				
			||||||
 | 
					 * copyright notice and this permission notice appear in all copies.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
				
			||||||
 | 
					 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
				
			||||||
 | 
					 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
				
			||||||
 | 
					 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
				
			||||||
 | 
					 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/unaligned.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/delay.h>
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/spi/spi.h>
 | 
				
			||||||
 | 
					#include <linux/platform_data/b53.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "b53_priv.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define B53_SPI_DATA		0xf0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define B53_SPI_STATUS		0xfe
 | 
				
			||||||
 | 
					#define B53_SPI_CMD_SPIF	BIT(7)
 | 
				
			||||||
 | 
					#define B53_SPI_CMD_RACK	BIT(5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define B53_SPI_CMD_READ	0x00
 | 
				
			||||||
 | 
					#define B53_SPI_CMD_WRITE	0x01
 | 
				
			||||||
 | 
					#define B53_SPI_CMD_NORMAL	0x60
 | 
				
			||||||
 | 
					#define B53_SPI_CMD_FAST	0x10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define B53_SPI_PAGE_SELECT	0xff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val,
 | 
				
			||||||
 | 
									   unsigned int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 txbuf[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ;
 | 
				
			||||||
 | 
						txbuf[1] = reg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return spi_write_then_read(spi, txbuf, 2, val, len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int b53_spi_clear_status(struct spi_device *spi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						u8 rxbuf;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < 10; i++) {
 | 
				
			||||||
 | 
							ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!(rxbuf & B53_SPI_CMD_SPIF))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							mdelay(1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (i == 10)
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int b53_spi_set_page(struct spi_device *spi, u8 page)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 txbuf[3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 | 
				
			||||||
 | 
						txbuf[1] = B53_SPI_PAGE_SELECT;
 | 
				
			||||||
 | 
						txbuf[2] = page;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return spi_write(spi, txbuf, sizeof(txbuf));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret = b53_spi_clear_status(spi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b53_spi_set_page(spi, page);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 rxbuf;
 | 
				
			||||||
 | 
						int retry_count;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_spi_read_reg(spi, reg, &rxbuf, 1);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (retry_count = 0; retry_count < 10; retry_count++) {
 | 
				
			||||||
 | 
							ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (rxbuf & B53_SPI_CMD_RACK)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							mdelay(1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (retry_count == 10)
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data,
 | 
				
			||||||
 | 
								unsigned int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spi_device *spi = dev->priv;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_prepare_reg_access(spi, page);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_spi_prepare_reg_read(spi, reg);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b53_spi_read_reg(spi, B53_SPI_DATA, data, len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return b53_spi_read(dev, page, reg, val, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ret)
 | 
				
			||||||
 | 
							*val = le16_to_cpu(*val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ret)
 | 
				
			||||||
 | 
							*val = le32_to_cpu(*val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*val = 0;
 | 
				
			||||||
 | 
						ret = b53_spi_read(dev, page, reg, (u8 *)val, 6);
 | 
				
			||||||
 | 
						if (!ret)
 | 
				
			||||||
 | 
							*val = le64_to_cpu(*val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ret)
 | 
				
			||||||
 | 
							*val = le64_to_cpu(*val);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spi_device *spi = dev->priv;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						u8 txbuf[3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_prepare_reg_access(spi, page);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 | 
				
			||||||
 | 
						txbuf[1] = reg;
 | 
				
			||||||
 | 
						txbuf[2] = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return spi_write(spi, txbuf, sizeof(txbuf));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spi_device *spi = dev->priv;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						u8 txbuf[4];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_prepare_reg_access(spi, page);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 | 
				
			||||||
 | 
						txbuf[1] = reg;
 | 
				
			||||||
 | 
						put_unaligned_le16(value, &txbuf[2]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return spi_write(spi, txbuf, sizeof(txbuf));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spi_device *spi = dev->priv;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						u8 txbuf[6];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_prepare_reg_access(spi, page);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 | 
				
			||||||
 | 
						txbuf[1] = reg;
 | 
				
			||||||
 | 
						put_unaligned_le32(value, &txbuf[2]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return spi_write(spi, txbuf, sizeof(txbuf));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spi_device *spi = dev->priv;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						u8 txbuf[10];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_prepare_reg_access(spi, page);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 | 
				
			||||||
 | 
						txbuf[1] = reg;
 | 
				
			||||||
 | 
						put_unaligned_le64(value, &txbuf[2]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return spi_write(spi, txbuf, sizeof(txbuf) - 2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spi_device *spi = dev->priv;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						u8 txbuf[10];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_prepare_reg_access(spi, page);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
 | 
				
			||||||
 | 
						txbuf[1] = reg;
 | 
				
			||||||
 | 
						put_unaligned_le64(value, &txbuf[2]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return spi_write(spi, txbuf, sizeof(txbuf));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct b53_io_ops b53_spi_ops = {
 | 
				
			||||||
 | 
						.read8 = b53_spi_read8,
 | 
				
			||||||
 | 
						.read16 = b53_spi_read16,
 | 
				
			||||||
 | 
						.read32 = b53_spi_read32,
 | 
				
			||||||
 | 
						.read48 = b53_spi_read48,
 | 
				
			||||||
 | 
						.read64 = b53_spi_read64,
 | 
				
			||||||
 | 
						.write8 = b53_spi_write8,
 | 
				
			||||||
 | 
						.write16 = b53_spi_write16,
 | 
				
			||||||
 | 
						.write32 = b53_spi_write32,
 | 
				
			||||||
 | 
						.write48 = b53_spi_write48,
 | 
				
			||||||
 | 
						.write64 = b53_spi_write64,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_spi_probe(struct spi_device *spi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_device *dev;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi);
 | 
				
			||||||
 | 
						if (!dev)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (spi->dev.platform_data)
 | 
				
			||||||
 | 
							dev->pdata = spi->dev.platform_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_switch_register(dev);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spi_set_drvdata(spi, dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_spi_remove(struct spi_device *spi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_device *dev = spi_get_drvdata(spi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dev)
 | 
				
			||||||
 | 
							b53_switch_remove(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct spi_driver b53_spi_driver = {
 | 
				
			||||||
 | 
						.driver = {
 | 
				
			||||||
 | 
							.name	= "b53-switch",
 | 
				
			||||||
 | 
							.bus	= &spi_bus_type,
 | 
				
			||||||
 | 
							.owner	= THIS_MODULE,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						.probe	= b53_spi_probe,
 | 
				
			||||||
 | 
						.remove	= b53_spi_remove,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_spi_driver(b53_spi_driver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("B53 SPI access driver");
 | 
				
			||||||
 | 
					MODULE_LICENSE("Dual BSD/GPL");
 | 
				
			||||||
							
								
								
									
										415
									
								
								drivers/net/dsa/b53/b53_srab.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										415
									
								
								drivers/net/dsa/b53/b53_srab.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,415 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * B53 register access through Switch Register Access Bridge Registers
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission to use, copy, modify, and/or distribute this software for any
 | 
				
			||||||
 | 
					 * purpose with or without fee is hereby granted, provided that the above
 | 
				
			||||||
 | 
					 * copyright notice and this permission notice appear in all copies.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
				
			||||||
 | 
					 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
				
			||||||
 | 
					 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
				
			||||||
 | 
					 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
				
			||||||
 | 
					 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/delay.h>
 | 
				
			||||||
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
 | 
					#include <linux/platform_data/b53.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "b53_priv.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* command and status register of the SRAB */
 | 
				
			||||||
 | 
					#define B53_SRAB_CMDSTAT		0x2c
 | 
				
			||||||
 | 
					#define  B53_SRAB_CMDSTAT_RST		BIT(2)
 | 
				
			||||||
 | 
					#define  B53_SRAB_CMDSTAT_WRITE		BIT(1)
 | 
				
			||||||
 | 
					#define  B53_SRAB_CMDSTAT_GORDYN	BIT(0)
 | 
				
			||||||
 | 
					#define  B53_SRAB_CMDSTAT_PAGE		24
 | 
				
			||||||
 | 
					#define  B53_SRAB_CMDSTAT_REG		16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* high order word of write data to switch registe */
 | 
				
			||||||
 | 
					#define B53_SRAB_WD_H			0x30
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* low order word of write data to switch registe */
 | 
				
			||||||
 | 
					#define B53_SRAB_WD_L			0x34
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* high order word of read data from switch register */
 | 
				
			||||||
 | 
					#define B53_SRAB_RD_H			0x38
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* low order word of read data from switch register */
 | 
				
			||||||
 | 
					#define B53_SRAB_RD_L			0x3c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* command and status register of the SRAB */
 | 
				
			||||||
 | 
					#define B53_SRAB_CTRLS			0x40
 | 
				
			||||||
 | 
					#define  B53_SRAB_CTRLS_RCAREQ		BIT(3)
 | 
				
			||||||
 | 
					#define  B53_SRAB_CTRLS_RCAGNT		BIT(4)
 | 
				
			||||||
 | 
					#define  B53_SRAB_CTRLS_SW_INIT_DONE	BIT(6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* the register captures interrupt pulses from the switch */
 | 
				
			||||||
 | 
					#define B53_SRAB_INTR			0x44
 | 
				
			||||||
 | 
					#define  B53_SRAB_INTR_P(x)		BIT(x)
 | 
				
			||||||
 | 
					#define  B53_SRAB_SWITCH_PHY		BIT(8)
 | 
				
			||||||
 | 
					#define  B53_SRAB_1588_SYNC		BIT(9)
 | 
				
			||||||
 | 
					#define  B53_SRAB_IMP1_SLEEP_TIMER	BIT(10)
 | 
				
			||||||
 | 
					#define  B53_SRAB_P7_SLEEP_TIMER	BIT(11)
 | 
				
			||||||
 | 
					#define  B53_SRAB_IMP0_SLEEP_TIMER	BIT(12)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct b53_srab_priv {
 | 
				
			||||||
 | 
						void __iomem *regs;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_srab_request_grant(struct b53_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_srab_priv *priv = dev->priv;
 | 
				
			||||||
 | 
						u8 __iomem *regs = priv->regs;
 | 
				
			||||||
 | 
						u32 ctrls;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctrls = readl(regs + B53_SRAB_CTRLS);
 | 
				
			||||||
 | 
						ctrls |= B53_SRAB_CTRLS_RCAREQ;
 | 
				
			||||||
 | 
						writel(ctrls, regs + B53_SRAB_CTRLS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < 20; i++) {
 | 
				
			||||||
 | 
							ctrls = readl(regs + B53_SRAB_CTRLS);
 | 
				
			||||||
 | 
							if (ctrls & B53_SRAB_CTRLS_RCAGNT)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							usleep_range(10, 100);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (WARN_ON(i == 5))
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void b53_srab_release_grant(struct b53_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_srab_priv *priv = dev->priv;
 | 
				
			||||||
 | 
						u8 __iomem *regs = priv->regs;
 | 
				
			||||||
 | 
						u32 ctrls;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctrls = readl(regs + B53_SRAB_CTRLS);
 | 
				
			||||||
 | 
						ctrls &= ~B53_SRAB_CTRLS_RCAREQ;
 | 
				
			||||||
 | 
						writel(ctrls, regs + B53_SRAB_CTRLS);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_srab_priv *priv = dev->priv;
 | 
				
			||||||
 | 
						u8 __iomem *regs = priv->regs;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						u32 cmdstat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* set register address */
 | 
				
			||||||
 | 
						cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) |
 | 
				
			||||||
 | 
							  (reg << B53_SRAB_CMDSTAT_REG) |
 | 
				
			||||||
 | 
							  B53_SRAB_CMDSTAT_GORDYN |
 | 
				
			||||||
 | 
							  op;
 | 
				
			||||||
 | 
						writel(cmdstat, regs + B53_SRAB_CMDSTAT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* check if operation completed */
 | 
				
			||||||
 | 
						for (i = 0; i < 5; ++i) {
 | 
				
			||||||
 | 
							cmdstat = readl(regs + B53_SRAB_CMDSTAT);
 | 
				
			||||||
 | 
							if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							usleep_range(10, 100);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (WARN_ON(i == 5))
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_srab_priv *priv = dev->priv;
 | 
				
			||||||
 | 
						u8 __iomem *regs = priv->regs;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_request_grant(dev);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_op(dev, page, reg, 0);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*val = readl(regs + B53_SRAB_RD_L) & 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
 | 
						b53_srab_release_grant(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_srab_priv *priv = dev->priv;
 | 
				
			||||||
 | 
						u8 __iomem *regs = priv->regs;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_request_grant(dev);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_op(dev, page, reg, 0);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*val = readl(regs + B53_SRAB_RD_L) & 0xffff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
 | 
						b53_srab_release_grant(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_srab_priv *priv = dev->priv;
 | 
				
			||||||
 | 
						u8 __iomem *regs = priv->regs;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_request_grant(dev);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_op(dev, page, reg, 0);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*val = readl(regs + B53_SRAB_RD_L);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
 | 
						b53_srab_release_grant(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_srab_priv *priv = dev->priv;
 | 
				
			||||||
 | 
						u8 __iomem *regs = priv->regs;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_request_grant(dev);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_op(dev, page, reg, 0);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*val = readl(regs + B53_SRAB_RD_L);
 | 
				
			||||||
 | 
						*val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
 | 
						b53_srab_release_grant(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_srab_priv *priv = dev->priv;
 | 
				
			||||||
 | 
						u8 __iomem *regs = priv->regs;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_request_grant(dev);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_op(dev, page, reg, 0);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*val = readl(regs + B53_SRAB_RD_L);
 | 
				
			||||||
 | 
						*val += (u64)readl(regs + B53_SRAB_RD_H) << 32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
 | 
						b53_srab_release_grant(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_srab_priv *priv = dev->priv;
 | 
				
			||||||
 | 
						u8 __iomem *regs = priv->regs;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_request_grant(dev);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						writel(value, regs + B53_SRAB_WD_L);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
 | 
						b53_srab_release_grant(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								    u16 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_srab_priv *priv = dev->priv;
 | 
				
			||||||
 | 
						u8 __iomem *regs = priv->regs;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_request_grant(dev);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						writel(value, regs + B53_SRAB_WD_L);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
 | 
						b53_srab_release_grant(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								    u32 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_srab_priv *priv = dev->priv;
 | 
				
			||||||
 | 
						u8 __iomem *regs = priv->regs;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_request_grant(dev);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						writel(value, regs + B53_SRAB_WD_L);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
 | 
						b53_srab_release_grant(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								    u64 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_srab_priv *priv = dev->priv;
 | 
				
			||||||
 | 
						u8 __iomem *regs = priv->regs;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_request_grant(dev);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						writel((u32)value, regs + B53_SRAB_WD_L);
 | 
				
			||||||
 | 
						writel((u16)(value >> 32), regs + B53_SRAB_WD_H);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
 | 
						b53_srab_release_grant(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg,
 | 
				
			||||||
 | 
								    u64 value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_srab_priv *priv = dev->priv;
 | 
				
			||||||
 | 
						u8 __iomem *regs = priv->regs;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_request_grant(dev);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						writel((u32)value, regs + B53_SRAB_WD_L);
 | 
				
			||||||
 | 
						writel((u32)(value >> 32), regs + B53_SRAB_WD_H);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
 | 
						b53_srab_release_grant(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct b53_io_ops b53_srab_ops = {
 | 
				
			||||||
 | 
						.read8 = b53_srab_read8,
 | 
				
			||||||
 | 
						.read16 = b53_srab_read16,
 | 
				
			||||||
 | 
						.read32 = b53_srab_read32,
 | 
				
			||||||
 | 
						.read48 = b53_srab_read48,
 | 
				
			||||||
 | 
						.read64 = b53_srab_read64,
 | 
				
			||||||
 | 
						.write8 = b53_srab_write8,
 | 
				
			||||||
 | 
						.write16 = b53_srab_write16,
 | 
				
			||||||
 | 
						.write32 = b53_srab_write32,
 | 
				
			||||||
 | 
						.write48 = b53_srab_write48,
 | 
				
			||||||
 | 
						.write64 = b53_srab_write64,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_srab_probe(struct platform_device *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_srab_priv *priv;
 | 
				
			||||||
 | 
						struct b53_device *dev;
 | 
				
			||||||
 | 
						struct resource *r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!priv)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
				
			||||||
 | 
						priv->regs = devm_ioremap_resource(&pdev->dev, r);
 | 
				
			||||||
 | 
						if (IS_ERR(priv->regs))
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, priv);
 | 
				
			||||||
 | 
						if (!dev)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						platform_set_drvdata(pdev, dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return b53_switch_register(dev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int b53_srab_remove(struct platform_device *pdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct b53_device *dev = platform_get_drvdata(pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dev)
 | 
				
			||||||
 | 
							b53_switch_remove(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct of_device_id b53_srab_of_match[] = {
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm53010-srab" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm53011-srab" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm53012-srab" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm53018-srab" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm53019-srab" },
 | 
				
			||||||
 | 
						{ .compatible = "brcm,bcm5301x-srab" },
 | 
				
			||||||
 | 
						{ /* sentinel */ },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct platform_driver b53_srab_driver = {
 | 
				
			||||||
 | 
						.probe = b53_srab_probe,
 | 
				
			||||||
 | 
						.remove = b53_srab_remove,
 | 
				
			||||||
 | 
						.driver = {
 | 
				
			||||||
 | 
							.name = "b53-srab-switch",
 | 
				
			||||||
 | 
							.of_match_table = b53_srab_of_match,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_platform_driver(b53_srab_driver);
 | 
				
			||||||
 | 
					MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver");
 | 
				
			||||||
 | 
					MODULE_LICENSE("Dual BSD/GPL");
 | 
				
			||||||
							
								
								
									
										33
									
								
								include/linux/platform_data/b53.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								include/linux/platform_data/b53.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,33 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * B53 platform data
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission to use, copy, modify, and/or distribute this software for any
 | 
				
			||||||
 | 
					 * purpose with or without fee is hereby granted, provided that the above
 | 
				
			||||||
 | 
					 * copyright notice and this permission notice appear in all copies.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
				
			||||||
 | 
					 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
				
			||||||
 | 
					 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
				
			||||||
 | 
					 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
				
			||||||
 | 
					 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
				
			||||||
 | 
					 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __B53_H
 | 
				
			||||||
 | 
					#define __B53_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct b53_platform_data {
 | 
				
			||||||
 | 
						u32 chip_id;
 | 
				
			||||||
 | 
						u16 enabled_ports;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* only used by MMAP'd driver */
 | 
				
			||||||
 | 
						unsigned big_endian:1;
 | 
				
			||||||
 | 
						void __iomem *regs;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		Loading…
	
		Reference in a new issue