Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Florian Fainelli and committed by
David S. Miller
967dd82f 409a5f27

+3397
+88
Documentation/devicetree/bindings/net/dsa/b53.txt
··· 1 + Broadcom BCM53xx Ethernet switches 2 + ================================== 3 + 4 + Required properties: 5 + 6 + - compatible: For external switch chips, compatible string must be exactly one 7 + of: "brcm,bcm5325" 8 + "brcm,bcm53115" 9 + "brcm,bcm53125" 10 + "brcm,bcm53128" 11 + "brcm,bcm5365" 12 + "brcm,bcm5395" 13 + "brcm,bcm5397" 14 + "brcm,bcm5398" 15 + 16 + For the BCM5310x SoCs with an integrated switch, must be one of: 17 + "brcm,bcm53010-srab" 18 + "brcm,bcm53011-srab" 19 + "brcm,bcm53012-srab" 20 + "brcm,bcm53018-srab" 21 + "brcm,bcm53019-srab" and the mandatory "brcm,bcm5301x-srab" string 22 + 23 + For the BCM63xx/33xx SoCs with an integrated switch, must be one of: 24 + "brcm,bcm3384-switch" 25 + "brcm,bcm6328-switch" 26 + "brcm,bcm6368-switch" and the mandatory "brcm,bcm63xx-switch" 27 + 28 + See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional 29 + required and optional properties. 30 + 31 + Examples: 32 + 33 + Ethernet switch connected via MDIO to the host, CPU port wired to eth0: 34 + 35 + eth0: ethernet@10001000 { 36 + compatible = "brcm,unimac"; 37 + reg = <0x10001000 0x1000>; 38 + 39 + fixed-link { 40 + speed = <1000>; 41 + duplex-full; 42 + }; 43 + }; 44 + 45 + mdio0: mdio@10000000 { 46 + compatible = "brcm,unimac-mdio"; 47 + #address-cells = <1>; 48 + #size-cells = <0>; 49 + 50 + switch0: ethernet-switch@30 { 51 + compatible = "brcm,bcm53125"; 52 + #address-cells = <1>; 53 + #size-cells = <0>; 54 + 55 + ports { 56 + port0@0 { 57 + reg = <0>; 58 + label = "lan1"; 59 + }; 60 + 61 + port1@1 { 62 + reg = <1>; 63 + label = "lan2"; 64 + }; 65 + 66 + port5@5 { 67 + reg = <5>; 68 + label = "cable-modem"; 69 + fixed-link { 70 + speed = <1000>; 71 + duplex-full; 72 + }; 73 + phy-mode = "rgmii-txid"; 74 + }; 75 + 76 + port8@8 { 77 + reg = <8>; 78 + label = "cpu"; 79 + fixed-link { 80 + speed = <1000>; 81 + duplex-full; 82 + }; 83 + phy-mode = "rgmii-txid"; 84 + ethernet = <&eth0>; 85 + }; 86 + }; 87 + }; 88 + };
+8
MAINTAINERS
··· 2454 2454 S: Supported 2455 2455 F: drivers/net/ethernet/broadcom/b44.* 2456 2456 2457 + BROADCOM B53 ETHERNET SWITCH DRIVER 2458 + M: Florian Fainelli <f.fainelli@gmail.com> 2459 + L: netdev@vger.kernel.org 2460 + L: openwrt-devel@lists.openwrt.org (subscribers-only) 2461 + S: Supported 2462 + F: drivers/net/dsa/b53/* 2463 + F: include/linux/platform_data/b53.h 2464 + 2457 2465 BROADCOM GENET ETHERNET DRIVER 2458 2466 M: Florian Fainelli <f.fainelli@gmail.com> 2459 2467 L: netdev@vger.kernel.org
+2
drivers/net/dsa/Kconfig
··· 28 28 This enables support for the Broadcom Starfighter 2 Ethernet 29 29 switch chips. 30 30 31 + source "drivers/net/dsa/b53/Kconfig" 32 + 31 33 endmenu
+2
drivers/net/dsa/Makefile
··· 1 1 obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o 2 2 obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o 3 3 obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm_sf2.o 4 + 5 + obj-y += b53/
+33
drivers/net/dsa/b53/Kconfig
··· 1 + menuconfig B53 2 + tristate "Broadcom BCM53xx managed switch support" 3 + depends on NET_DSA 4 + help 5 + This driver adds support for Broadcom managed switch chips. It supports 6 + BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX 7 + integrated switches. 8 + 9 + config B53_SPI_DRIVER 10 + tristate "B53 SPI connected switch driver" 11 + depends on B53 && SPI 12 + help 13 + Select to enable support for registering switches configured through SPI. 14 + 15 + config B53_MDIO_DRIVER 16 + tristate "B53 MDIO connected switch driver" 17 + depends on B53 18 + help 19 + Select to enable support for registering switches configured through MDIO. 20 + 21 + config B53_MMAP_DRIVER 22 + tristate "B53 MMAP connected switch driver" 23 + depends on B53 && HAS_IOMEM 24 + help 25 + Select to enable support for memory-mapped switches like the BCM63XX 26 + integrated switches. 27 + 28 + config B53_SRAB_DRIVER 29 + tristate "B53 SRAB connected switch driver" 30 + depends on B53 && HAS_IOMEM 31 + help 32 + Select to enable support for memory-mapped Switch Register Access 33 + Bridge Registers (SRAB) like it is found on the BCM53010
+6
drivers/net/dsa/b53/Makefile
··· 1 + obj-$(CONFIG_B53) += b53_common.o 2 + 3 + obj-$(CONFIG_B53_SPI_DRIVER) += b53_spi.o 4 + obj-$(CONFIG_B53_MDIO_DRIVER) += b53_mdio.o 5 + obj-$(CONFIG_B53_MMAP_DRIVER) += b53_mmap.o 6 + obj-$(CONFIG_B53_SRAB_DRIVER) += b53_srab.o
+1158
drivers/net/dsa/b53/b53_common.c
··· 1 + /* 2 + * B53 switch driver main logic 3 + * 4 + * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org> 5 + * Copyright (C) 2016 Florian Fainelli <f.fainelli@gmail.com> 6 + * 7 + * Permission to use, copy, modify, and/or distribute this software for any 8 + * purpose with or without fee is hereby granted, provided that the above 9 + * copyright notice and this permission notice appear in all copies. 10 + * 11 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 + */ 19 + 20 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 21 + 22 + #include <linux/delay.h> 23 + #include <linux/export.h> 24 + #include <linux/gpio.h> 25 + #include <linux/kernel.h> 26 + #include <linux/module.h> 27 + #include <linux/platform_data/b53.h> 28 + #include <linux/phy.h> 29 + #include <net/dsa.h> 30 + 31 + #include "b53_regs.h" 32 + #include "b53_priv.h" 33 + 34 + struct b53_mib_desc { 35 + u8 size; 36 + u8 offset; 37 + const char *name; 38 + }; 39 + 40 + /* BCM5365 MIB counters */ 41 + static const struct b53_mib_desc b53_mibs_65[] = { 42 + { 8, 0x00, "TxOctets" }, 43 + { 4, 0x08, "TxDropPkts" }, 44 + { 4, 0x10, "TxBroadcastPkts" }, 45 + { 4, 0x14, "TxMulticastPkts" }, 46 + { 4, 0x18, "TxUnicastPkts" }, 47 + { 4, 0x1c, "TxCollisions" }, 48 + { 4, 0x20, "TxSingleCollision" }, 49 + { 4, 0x24, "TxMultipleCollision" }, 50 + { 4, 0x28, "TxDeferredTransmit" }, 51 + { 4, 0x2c, "TxLateCollision" }, 52 + { 4, 0x30, "TxExcessiveCollision" }, 53 + { 4, 0x38, "TxPausePkts" }, 54 + { 8, 0x44, "RxOctets" }, 55 + { 4, 0x4c, "RxUndersizePkts" }, 56 + { 4, 0x50, "RxPausePkts" }, 57 + { 4, 0x54, "Pkts64Octets" }, 58 + { 4, 0x58, "Pkts65to127Octets" }, 59 + { 4, 0x5c, "Pkts128to255Octets" }, 60 + { 4, 0x60, "Pkts256to511Octets" }, 61 + { 4, 0x64, "Pkts512to1023Octets" }, 62 + { 4, 0x68, "Pkts1024to1522Octets" }, 63 + { 4, 0x6c, "RxOversizePkts" }, 64 + { 4, 0x70, "RxJabbers" }, 65 + { 4, 0x74, "RxAlignmentErrors" }, 66 + { 4, 0x78, "RxFCSErrors" }, 67 + { 8, 0x7c, "RxGoodOctets" }, 68 + { 4, 0x84, "RxDropPkts" }, 69 + { 4, 0x88, "RxUnicastPkts" }, 70 + { 4, 0x8c, "RxMulticastPkts" }, 71 + { 4, 0x90, "RxBroadcastPkts" }, 72 + { 4, 0x94, "RxSAChanges" }, 73 + { 4, 0x98, "RxFragments" }, 74 + }; 75 + 76 + #define B53_MIBS_65_SIZE ARRAY_SIZE(b53_mibs_65) 77 + 78 + /* BCM63xx MIB counters */ 79 + static const struct b53_mib_desc b53_mibs_63xx[] = { 80 + { 8, 0x00, "TxOctets" }, 81 + { 4, 0x08, "TxDropPkts" }, 82 + { 4, 0x0c, "TxQoSPkts" }, 83 + { 4, 0x10, "TxBroadcastPkts" }, 84 + { 4, 0x14, "TxMulticastPkts" }, 85 + { 4, 0x18, "TxUnicastPkts" }, 86 + { 4, 0x1c, "TxCollisions" }, 87 + { 4, 0x20, "TxSingleCollision" }, 88 + { 4, 0x24, "TxMultipleCollision" }, 89 + { 4, 0x28, "TxDeferredTransmit" }, 90 + { 4, 0x2c, "TxLateCollision" }, 91 + { 4, 0x30, "TxExcessiveCollision" }, 92 + { 4, 0x38, "TxPausePkts" }, 93 + { 8, 0x3c, "TxQoSOctets" }, 94 + { 8, 0x44, "RxOctets" }, 95 + { 4, 0x4c, "RxUndersizePkts" }, 96 + { 4, 0x50, "RxPausePkts" }, 97 + { 4, 0x54, "Pkts64Octets" }, 98 + { 4, 0x58, "Pkts65to127Octets" }, 99 + { 4, 0x5c, "Pkts128to255Octets" }, 100 + { 4, 0x60, "Pkts256to511Octets" }, 101 + { 4, 0x64, "Pkts512to1023Octets" }, 102 + { 4, 0x68, "Pkts1024to1522Octets" }, 103 + { 4, 0x6c, "RxOversizePkts" }, 104 + { 4, 0x70, "RxJabbers" }, 105 + { 4, 0x74, "RxAlignmentErrors" }, 106 + { 4, 0x78, "RxFCSErrors" }, 107 + { 8, 0x7c, "RxGoodOctets" }, 108 + { 4, 0x84, "RxDropPkts" }, 109 + { 4, 0x88, "RxUnicastPkts" }, 110 + { 4, 0x8c, "RxMulticastPkts" }, 111 + { 4, 0x90, "RxBroadcastPkts" }, 112 + { 4, 0x94, "RxSAChanges" }, 113 + { 4, 0x98, "RxFragments" }, 114 + { 4, 0xa0, "RxSymbolErrors" }, 115 + { 4, 0xa4, "RxQoSPkts" }, 116 + { 8, 0xa8, "RxQoSOctets" }, 117 + { 4, 0xb0, "Pkts1523to2047Octets" }, 118 + { 4, 0xb4, "Pkts2048to4095Octets" }, 119 + { 4, 0xb8, "Pkts4096to8191Octets" }, 120 + { 4, 0xbc, "Pkts8192to9728Octets" }, 121 + { 4, 0xc0, "RxDiscarded" }, 122 + }; 123 + 124 + #define B53_MIBS_63XX_SIZE ARRAY_SIZE(b53_mibs_63xx) 125 + 126 + /* MIB counters */ 127 + static const struct b53_mib_desc b53_mibs[] = { 128 + { 8, 0x00, "TxOctets" }, 129 + { 4, 0x08, "TxDropPkts" }, 130 + { 4, 0x10, "TxBroadcastPkts" }, 131 + { 4, 0x14, "TxMulticastPkts" }, 132 + { 4, 0x18, "TxUnicastPkts" }, 133 + { 4, 0x1c, "TxCollisions" }, 134 + { 4, 0x20, "TxSingleCollision" }, 135 + { 4, 0x24, "TxMultipleCollision" }, 136 + { 4, 0x28, "TxDeferredTransmit" }, 137 + { 4, 0x2c, "TxLateCollision" }, 138 + { 4, 0x30, "TxExcessiveCollision" }, 139 + { 4, 0x38, "TxPausePkts" }, 140 + { 8, 0x50, "RxOctets" }, 141 + { 4, 0x58, "RxUndersizePkts" }, 142 + { 4, 0x5c, "RxPausePkts" }, 143 + { 4, 0x60, "Pkts64Octets" }, 144 + { 4, 0x64, "Pkts65to127Octets" }, 145 + { 4, 0x68, "Pkts128to255Octets" }, 146 + { 4, 0x6c, "Pkts256to511Octets" }, 147 + { 4, 0x70, "Pkts512to1023Octets" }, 148 + { 4, 0x74, "Pkts1024to1522Octets" }, 149 + { 4, 0x78, "RxOversizePkts" }, 150 + { 4, 0x7c, "RxJabbers" }, 151 + { 4, 0x80, "RxAlignmentErrors" }, 152 + { 4, 0x84, "RxFCSErrors" }, 153 + { 8, 0x88, "RxGoodOctets" }, 154 + { 4, 0x90, "RxDropPkts" }, 155 + { 4, 0x94, "RxUnicastPkts" }, 156 + { 4, 0x98, "RxMulticastPkts" }, 157 + { 4, 0x9c, "RxBroadcastPkts" }, 158 + { 4, 0xa0, "RxSAChanges" }, 159 + { 4, 0xa4, "RxFragments" }, 160 + { 4, 0xa8, "RxJumboPkts" }, 161 + { 4, 0xac, "RxSymbolErrors" }, 162 + { 4, 0xc0, "RxDiscarded" }, 163 + }; 164 + 165 + #define B53_MIBS_SIZE ARRAY_SIZE(b53_mibs) 166 + 167 + static int b53_do_vlan_op(struct b53_device *dev, u8 op) 168 + { 169 + unsigned int i; 170 + 171 + b53_write8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], VTA_START_CMD | op); 172 + 173 + for (i = 0; i < 10; i++) { 174 + u8 vta; 175 + 176 + b53_read8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], &vta); 177 + if (!(vta & VTA_START_CMD)) 178 + return 0; 179 + 180 + usleep_range(100, 200); 181 + } 182 + 183 + return -EIO; 184 + } 185 + 186 + static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members, 187 + u16 untag) 188 + { 189 + if (is5325(dev)) { 190 + u32 entry = 0; 191 + 192 + if (members) { 193 + entry = ((untag & VA_UNTAG_MASK_25) << VA_UNTAG_S_25) | 194 + members; 195 + if (dev->core_rev >= 3) 196 + entry |= VA_VALID_25_R4 | vid << VA_VID_HIGH_S; 197 + else 198 + entry |= VA_VALID_25; 199 + } 200 + 201 + b53_write32(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_25, entry); 202 + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, vid | 203 + VTA_RW_STATE_WR | VTA_RW_OP_EN); 204 + } else if (is5365(dev)) { 205 + u16 entry = 0; 206 + 207 + if (members) 208 + entry = ((untag & VA_UNTAG_MASK_65) << VA_UNTAG_S_65) | 209 + members | VA_VALID_65; 210 + 211 + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_65, entry); 212 + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_65, vid | 213 + VTA_RW_STATE_WR | VTA_RW_OP_EN); 214 + } else { 215 + b53_write16(dev, B53_ARLIO_PAGE, dev->vta_regs[1], vid); 216 + b53_write32(dev, B53_ARLIO_PAGE, dev->vta_regs[2], 217 + (untag << VTE_UNTAG_S) | members); 218 + 219 + b53_do_vlan_op(dev, VTA_CMD_WRITE); 220 + } 221 + } 222 + 223 + void b53_set_forwarding(struct b53_device *dev, int enable) 224 + { 225 + u8 mgmt; 226 + 227 + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); 228 + 229 + if (enable) 230 + mgmt |= SM_SW_FWD_EN; 231 + else 232 + mgmt &= ~SM_SW_FWD_EN; 233 + 234 + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); 235 + } 236 + 237 + static void b53_enable_vlan(struct b53_device *dev, int enable) 238 + { 239 + u8 mgmt, vc0, vc1, vc4 = 0, vc5; 240 + 241 + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); 242 + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, &vc0); 243 + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, &vc1); 244 + 245 + if (is5325(dev) || is5365(dev)) { 246 + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4); 247 + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, &vc5); 248 + } else if (is63xx(dev)) { 249 + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, &vc4); 250 + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, &vc5); 251 + } else { 252 + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, &vc4); 253 + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5); 254 + } 255 + 256 + mgmt &= ~SM_SW_FWD_MODE; 257 + 258 + if (enable) { 259 + vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID; 260 + vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN; 261 + vc4 &= ~VC4_ING_VID_CHECK_MASK; 262 + vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S; 263 + vc5 |= VC5_DROP_VTABLE_MISS; 264 + 265 + if (is5325(dev)) 266 + vc0 &= ~VC0_RESERVED_1; 267 + 268 + if (is5325(dev) || is5365(dev)) 269 + vc1 |= VC1_RX_MCST_TAG_EN; 270 + 271 + if (!is5325(dev) && !is5365(dev)) { 272 + if (dev->allow_vid_4095) 273 + vc5 |= VC5_VID_FFF_EN; 274 + else 275 + vc5 &= ~VC5_VID_FFF_EN; 276 + } 277 + } else { 278 + vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID); 279 + vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN); 280 + vc4 &= ~VC4_ING_VID_CHECK_MASK; 281 + vc5 &= ~VC5_DROP_VTABLE_MISS; 282 + 283 + if (is5325(dev) || is5365(dev)) 284 + vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S; 285 + else 286 + vc4 |= VC4_ING_VID_VIO_TO_IMP << VC4_ING_VID_CHECK_S; 287 + 288 + if (is5325(dev) || is5365(dev)) 289 + vc1 &= ~VC1_RX_MCST_TAG_EN; 290 + 291 + if (!is5325(dev) && !is5365(dev)) 292 + vc5 &= ~VC5_VID_FFF_EN; 293 + } 294 + 295 + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, vc0); 296 + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, vc1); 297 + 298 + if (is5325(dev) || is5365(dev)) { 299 + /* enable the high 8 bit vid check on 5325 */ 300 + if (is5325(dev) && enable) 301 + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 302 + VC3_HIGH_8BIT_EN); 303 + else 304 + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0); 305 + 306 + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, vc4); 307 + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, vc5); 308 + } else if (is63xx(dev)) { 309 + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3_63XX, 0); 310 + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, vc4); 311 + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, vc5); 312 + } else { 313 + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0); 314 + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, vc4); 315 + b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, vc5); 316 + } 317 + 318 + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); 319 + } 320 + 321 + static int b53_set_jumbo(struct b53_device *dev, bool enable, bool allow_10_100) 322 + { 323 + u32 port_mask = 0; 324 + u16 max_size = JMS_MIN_SIZE; 325 + 326 + if (is5325(dev) || is5365(dev)) 327 + return -EINVAL; 328 + 329 + if (enable) { 330 + port_mask = dev->enabled_ports; 331 + max_size = JMS_MAX_SIZE; 332 + if (allow_10_100) 333 + port_mask |= JPM_10_100_JUMBO_EN; 334 + } 335 + 336 + b53_write32(dev, B53_JUMBO_PAGE, dev->jumbo_pm_reg, port_mask); 337 + return b53_write16(dev, B53_JUMBO_PAGE, dev->jumbo_size_reg, max_size); 338 + } 339 + 340 + static int b53_flush_arl(struct b53_device *dev) 341 + { 342 + unsigned int i; 343 + 344 + b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, 345 + FAST_AGE_DONE | FAST_AGE_DYNAMIC | FAST_AGE_STATIC); 346 + 347 + for (i = 0; i < 10; i++) { 348 + u8 fast_age_ctrl; 349 + 350 + b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, 351 + &fast_age_ctrl); 352 + 353 + if (!(fast_age_ctrl & FAST_AGE_DONE)) 354 + goto out; 355 + 356 + msleep(1); 357 + } 358 + 359 + return -ETIMEDOUT; 360 + out: 361 + /* Only age dynamic entries (default behavior) */ 362 + b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, FAST_AGE_DYNAMIC); 363 + return 0; 364 + } 365 + 366 + static int b53_enable_port(struct dsa_switch *ds, int port, 367 + struct phy_device *phy) 368 + { 369 + struct b53_device *dev = ds_to_priv(ds); 370 + 371 + /* Clear the Rx and Tx disable bits and set to no spanning tree */ 372 + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), 0); 373 + 374 + return 0; 375 + } 376 + 377 + static void b53_disable_port(struct dsa_switch *ds, int port, 378 + struct phy_device *phy) 379 + { 380 + struct b53_device *dev = ds_to_priv(ds); 381 + u8 reg; 382 + 383 + /* Disable Tx/Rx for the port */ 384 + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), &reg); 385 + reg |= PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE; 386 + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), reg); 387 + } 388 + 389 + static void b53_enable_cpu_port(struct b53_device *dev) 390 + { 391 + unsigned int cpu_port = dev->cpu_port; 392 + u8 port_ctrl; 393 + 394 + /* BCM5325 CPU port is at 8 */ 395 + if ((is5325(dev) || is5365(dev)) && cpu_port == B53_CPU_PORT_25) 396 + cpu_port = B53_CPU_PORT; 397 + 398 + port_ctrl = PORT_CTRL_RX_BCST_EN | 399 + PORT_CTRL_RX_MCST_EN | 400 + PORT_CTRL_RX_UCST_EN; 401 + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(cpu_port), port_ctrl); 402 + } 403 + 404 + static void b53_enable_mib(struct b53_device *dev) 405 + { 406 + u8 gc; 407 + 408 + b53_read8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); 409 + gc &= ~(GC_RESET_MIB | GC_MIB_AC_EN); 410 + b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc); 411 + } 412 + 413 + static int b53_configure_vlan(struct b53_device *dev) 414 + { 415 + int i; 416 + 417 + /* clear all vlan entries */ 418 + if (is5325(dev) || is5365(dev)) { 419 + for (i = 1; i < dev->num_vlans; i++) 420 + b53_set_vlan_entry(dev, i, 0, 0); 421 + } else { 422 + b53_do_vlan_op(dev, VTA_CMD_CLEAR); 423 + } 424 + 425 + b53_enable_vlan(dev, false); 426 + 427 + b53_for_each_port(dev, i) 428 + b53_write16(dev, B53_VLAN_PAGE, 429 + B53_VLAN_PORT_DEF_TAG(i), 1); 430 + 431 + if (!is5325(dev) && !is5365(dev)) 432 + b53_set_jumbo(dev, dev->enable_jumbo, false); 433 + 434 + return 0; 435 + } 436 + 437 + static void b53_switch_reset_gpio(struct b53_device *dev) 438 + { 439 + int gpio = dev->reset_gpio; 440 + 441 + if (gpio < 0) 442 + return; 443 + 444 + /* Reset sequence: RESET low(50ms)->high(20ms) 445 + */ 446 + gpio_set_value(gpio, 0); 447 + mdelay(50); 448 + 449 + gpio_set_value(gpio, 1); 450 + mdelay(20); 451 + 452 + dev->current_page = 0xff; 453 + } 454 + 455 + static int b53_switch_reset(struct b53_device *dev) 456 + { 457 + u8 mgmt; 458 + 459 + b53_switch_reset_gpio(dev); 460 + 461 + if (is539x(dev)) { 462 + b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x83); 463 + b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x00); 464 + } 465 + 466 + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); 467 + 468 + if (!(mgmt & SM_SW_FWD_EN)) { 469 + mgmt &= ~SM_SW_FWD_MODE; 470 + mgmt |= SM_SW_FWD_EN; 471 + 472 + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); 473 + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); 474 + 475 + if (!(mgmt & SM_SW_FWD_EN)) { 476 + dev_err(dev->dev, "Failed to enable switch!\n"); 477 + return -EINVAL; 478 + } 479 + } 480 + 481 + b53_enable_mib(dev); 482 + 483 + return b53_flush_arl(dev); 484 + } 485 + 486 + static int b53_phy_read16(struct dsa_switch *ds, int addr, int reg) 487 + { 488 + struct b53_device *priv = ds_to_priv(ds); 489 + u16 value = 0; 490 + int ret; 491 + 492 + if (priv->ops->phy_read16) 493 + ret = priv->ops->phy_read16(priv, addr, reg, &value); 494 + else 495 + ret = b53_read16(priv, B53_PORT_MII_PAGE(addr), 496 + reg * 2, &value); 497 + 498 + return ret ? ret : value; 499 + } 500 + 501 + static int b53_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) 502 + { 503 + struct b53_device *priv = ds_to_priv(ds); 504 + 505 + if (priv->ops->phy_write16) 506 + return priv->ops->phy_write16(priv, addr, reg, val); 507 + 508 + return b53_write16(priv, B53_PORT_MII_PAGE(addr), reg * 2, val); 509 + } 510 + 511 + static int b53_reset_switch(struct b53_device *priv) 512 + { 513 + /* reset vlans */ 514 + priv->enable_jumbo = false; 515 + 516 + memset(priv->ports, 0, sizeof(*priv->ports) * priv->num_ports); 517 + 518 + return b53_switch_reset(priv); 519 + } 520 + 521 + static int b53_apply_config(struct b53_device *priv) 522 + { 523 + /* disable switching */ 524 + b53_set_forwarding(priv, 0); 525 + 526 + b53_configure_vlan(priv); 527 + 528 + /* enable switching */ 529 + b53_set_forwarding(priv, 1); 530 + 531 + return 0; 532 + } 533 + 534 + static void b53_reset_mib(struct b53_device *priv) 535 + { 536 + u8 gc; 537 + 538 + b53_read8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); 539 + 540 + b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc | GC_RESET_MIB); 541 + msleep(1); 542 + b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc & ~GC_RESET_MIB); 543 + msleep(1); 544 + } 545 + 546 + static const struct b53_mib_desc *b53_get_mib(struct b53_device *dev) 547 + { 548 + if (is5365(dev)) 549 + return b53_mibs_65; 550 + else if (is63xx(dev)) 551 + return b53_mibs_63xx; 552 + else 553 + return b53_mibs; 554 + } 555 + 556 + static unsigned int b53_get_mib_size(struct b53_device *dev) 557 + { 558 + if (is5365(dev)) 559 + return B53_MIBS_65_SIZE; 560 + else if (is63xx(dev)) 561 + return B53_MIBS_63XX_SIZE; 562 + else 563 + return B53_MIBS_SIZE; 564 + } 565 + 566 + static void b53_get_strings(struct dsa_switch *ds, int port, uint8_t *data) 567 + { 568 + struct b53_device *dev = ds_to_priv(ds); 569 + const struct b53_mib_desc *mibs = b53_get_mib(dev); 570 + unsigned int mib_size = b53_get_mib_size(dev); 571 + unsigned int i; 572 + 573 + for (i = 0; i < mib_size; i++) 574 + memcpy(data + i * ETH_GSTRING_LEN, 575 + mibs[i].name, ETH_GSTRING_LEN); 576 + } 577 + 578 + static void b53_get_ethtool_stats(struct dsa_switch *ds, int port, 579 + uint64_t *data) 580 + { 581 + struct b53_device *dev = ds_to_priv(ds); 582 + const struct b53_mib_desc *mibs = b53_get_mib(dev); 583 + unsigned int mib_size = b53_get_mib_size(dev); 584 + const struct b53_mib_desc *s; 585 + unsigned int i; 586 + u64 val = 0; 587 + 588 + if (is5365(dev) && port == 5) 589 + port = 8; 590 + 591 + mutex_lock(&dev->stats_mutex); 592 + 593 + for (i = 0; i < mib_size; i++) { 594 + s = &mibs[i]; 595 + 596 + if (mibs->size == 8) { 597 + b53_read64(dev, B53_MIB_PAGE(port), s->offset, &val); 598 + } else { 599 + u32 val32; 600 + 601 + b53_read32(dev, B53_MIB_PAGE(port), s->offset, 602 + &val32); 603 + val = val32; 604 + } 605 + data[i] = (u64)val; 606 + } 607 + 608 + mutex_unlock(&dev->stats_mutex); 609 + } 610 + 611 + static int b53_get_sset_count(struct dsa_switch *ds) 612 + { 613 + struct b53_device *dev = ds_to_priv(ds); 614 + 615 + return b53_get_mib_size(dev); 616 + } 617 + 618 + static int b53_set_addr(struct dsa_switch *ds, u8 *addr) 619 + { 620 + return 0; 621 + } 622 + 623 + static int b53_setup(struct dsa_switch *ds) 624 + { 625 + struct b53_device *dev = ds_to_priv(ds); 626 + unsigned int port; 627 + int ret; 628 + 629 + ret = b53_reset_switch(dev); 630 + if (ret) { 631 + dev_err(ds->dev, "failed to reset switch\n"); 632 + return ret; 633 + } 634 + 635 + b53_reset_mib(dev); 636 + 637 + ret = b53_apply_config(dev); 638 + if (ret) 639 + dev_err(ds->dev, "failed to apply configuration\n"); 640 + 641 + for (port = 0; port < dev->num_ports; port++) { 642 + if (BIT(port) & ds->enabled_port_mask) 643 + b53_enable_port(ds, port, NULL); 644 + else if (dsa_is_cpu_port(ds, port)) 645 + b53_enable_cpu_port(dev); 646 + else 647 + b53_disable_port(ds, port, NULL); 648 + } 649 + 650 + return ret; 651 + } 652 + 653 + static void b53_adjust_link(struct dsa_switch *ds, int port, 654 + struct phy_device *phydev) 655 + { 656 + struct b53_device *dev = ds_to_priv(ds); 657 + u8 rgmii_ctrl = 0, reg = 0, off; 658 + 659 + if (!phy_is_pseudo_fixed_link(phydev)) 660 + return; 661 + 662 + /* Override the port settings */ 663 + if (port == dev->cpu_port) { 664 + off = B53_PORT_OVERRIDE_CTRL; 665 + reg = PORT_OVERRIDE_EN; 666 + } else { 667 + off = B53_GMII_PORT_OVERRIDE_CTRL(port); 668 + reg = GMII_PO_EN; 669 + } 670 + 671 + /* Set the link UP */ 672 + if (phydev->link) 673 + reg |= PORT_OVERRIDE_LINK; 674 + 675 + if (phydev->duplex == DUPLEX_FULL) 676 + reg |= PORT_OVERRIDE_FULL_DUPLEX; 677 + 678 + switch (phydev->speed) { 679 + case 2000: 680 + reg |= PORT_OVERRIDE_SPEED_2000M; 681 + /* fallthrough */ 682 + case SPEED_1000: 683 + reg |= PORT_OVERRIDE_SPEED_1000M; 684 + break; 685 + case SPEED_100: 686 + reg |= PORT_OVERRIDE_SPEED_100M; 687 + break; 688 + case SPEED_10: 689 + reg |= PORT_OVERRIDE_SPEED_10M; 690 + break; 691 + default: 692 + dev_err(ds->dev, "unknown speed: %d\n", phydev->speed); 693 + return; 694 + } 695 + 696 + /* Enable flow control on BCM5301x's CPU port */ 697 + if (is5301x(dev) && port == dev->cpu_port) 698 + reg |= PORT_OVERRIDE_RX_FLOW | PORT_OVERRIDE_TX_FLOW; 699 + 700 + if (phydev->pause) { 701 + if (phydev->asym_pause) 702 + reg |= PORT_OVERRIDE_TX_FLOW; 703 + reg |= PORT_OVERRIDE_RX_FLOW; 704 + } 705 + 706 + b53_write8(dev, B53_CTRL_PAGE, off, reg); 707 + 708 + if (is531x5(dev) && phy_interface_is_rgmii(phydev)) { 709 + if (port == 8) 710 + off = B53_RGMII_CTRL_IMP; 711 + else 712 + off = B53_RGMII_CTRL_P(port); 713 + 714 + /* Configure the port RGMII clock delay by DLL disabled and 715 + * tx_clk aligned timing (restoring to reset defaults) 716 + */ 717 + b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl); 718 + rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC | 719 + RGMII_CTRL_TIMING_SEL); 720 + 721 + /* PHY_INTERFACE_MODE_RGMII_TXID means TX internal delay, make 722 + * sure that we enable the port TX clock internal delay to 723 + * account for this internal delay that is inserted, otherwise 724 + * the switch won't be able to receive correctly. 725 + * 726 + * PHY_INTERFACE_MODE_RGMII means that we are not introducing 727 + * any delay neither on transmission nor reception, so the 728 + * BCM53125 must also be configured accordingly to account for 729 + * the lack of delay and introduce 730 + * 731 + * The BCM53125 switch has its RX clock and TX clock control 732 + * swapped, hence the reason why we modify the TX clock path in 733 + * the "RGMII" case 734 + */ 735 + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 736 + rgmii_ctrl |= RGMII_CTRL_DLL_TXC; 737 + if (phydev->interface == PHY_INTERFACE_MODE_RGMII) 738 + rgmii_ctrl |= RGMII_CTRL_DLL_TXC | RGMII_CTRL_DLL_RXC; 739 + rgmii_ctrl |= RGMII_CTRL_TIMING_SEL; 740 + b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl); 741 + 742 + dev_info(ds->dev, "Configured port %d for %s\n", port, 743 + phy_modes(phydev->interface)); 744 + } 745 + 746 + /* configure MII port if necessary */ 747 + if (is5325(dev)) { 748 + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, 749 + &reg); 750 + 751 + /* reverse mii needs to be enabled */ 752 + if (!(reg & PORT_OVERRIDE_RV_MII_25)) { 753 + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, 754 + reg | PORT_OVERRIDE_RV_MII_25); 755 + b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, 756 + &reg); 757 + 758 + if (!(reg & PORT_OVERRIDE_RV_MII_25)) { 759 + dev_err(ds->dev, 760 + "Failed to enable reverse MII mode\n"); 761 + return; 762 + } 763 + } 764 + } else if (is5301x(dev)) { 765 + if (port != dev->cpu_port) { 766 + u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(dev->cpu_port); 767 + u8 gmii_po; 768 + 769 + b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po); 770 + gmii_po |= GMII_PO_LINK | 771 + GMII_PO_RX_FLOW | 772 + GMII_PO_TX_FLOW | 773 + GMII_PO_EN | 774 + GMII_PO_SPEED_2000M; 775 + b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po); 776 + } 777 + } 778 + } 779 + 780 + static struct dsa_switch_driver b53_switch_ops = { 781 + .tag_protocol = DSA_TAG_PROTO_NONE, 782 + .setup = b53_setup, 783 + .set_addr = b53_set_addr, 784 + .get_strings = b53_get_strings, 785 + .get_ethtool_stats = b53_get_ethtool_stats, 786 + .get_sset_count = b53_get_sset_count, 787 + .phy_read = b53_phy_read16, 788 + .phy_write = b53_phy_write16, 789 + .adjust_link = b53_adjust_link, 790 + .port_enable = b53_enable_port, 791 + .port_disable = b53_disable_port, 792 + }; 793 + 794 + struct b53_chip_data { 795 + u32 chip_id; 796 + const char *dev_name; 797 + u16 vlans; 798 + u16 enabled_ports; 799 + u8 cpu_port; 800 + u8 vta_regs[3]; 801 + u8 duplex_reg; 802 + u8 jumbo_pm_reg; 803 + u8 jumbo_size_reg; 804 + }; 805 + 806 + #define B53_VTA_REGS \ 807 + { B53_VT_ACCESS, B53_VT_INDEX, B53_VT_ENTRY } 808 + #define B53_VTA_REGS_9798 \ 809 + { B53_VT_ACCESS_9798, B53_VT_INDEX_9798, B53_VT_ENTRY_9798 } 810 + #define B53_VTA_REGS_63XX \ 811 + { B53_VT_ACCESS_63XX, B53_VT_INDEX_63XX, B53_VT_ENTRY_63XX } 812 + 813 + static const struct b53_chip_data b53_switch_chips[] = { 814 + { 815 + .chip_id = BCM5325_DEVICE_ID, 816 + .dev_name = "BCM5325", 817 + .vlans = 16, 818 + .enabled_ports = 0x1f, 819 + .cpu_port = B53_CPU_PORT_25, 820 + .duplex_reg = B53_DUPLEX_STAT_FE, 821 + }, 822 + { 823 + .chip_id = BCM5365_DEVICE_ID, 824 + .dev_name = "BCM5365", 825 + .vlans = 256, 826 + .enabled_ports = 0x1f, 827 + .cpu_port = B53_CPU_PORT_25, 828 + .duplex_reg = B53_DUPLEX_STAT_FE, 829 + }, 830 + { 831 + .chip_id = BCM5395_DEVICE_ID, 832 + .dev_name = "BCM5395", 833 + .vlans = 4096, 834 + .enabled_ports = 0x1f, 835 + .cpu_port = B53_CPU_PORT, 836 + .vta_regs = B53_VTA_REGS, 837 + .duplex_reg = B53_DUPLEX_STAT_GE, 838 + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 839 + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 840 + }, 841 + { 842 + .chip_id = BCM5397_DEVICE_ID, 843 + .dev_name = "BCM5397", 844 + .vlans = 4096, 845 + .enabled_ports = 0x1f, 846 + .cpu_port = B53_CPU_PORT, 847 + .vta_regs = B53_VTA_REGS_9798, 848 + .duplex_reg = B53_DUPLEX_STAT_GE, 849 + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 850 + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 851 + }, 852 + { 853 + .chip_id = BCM5398_DEVICE_ID, 854 + .dev_name = "BCM5398", 855 + .vlans = 4096, 856 + .enabled_ports = 0x7f, 857 + .cpu_port = B53_CPU_PORT, 858 + .vta_regs = B53_VTA_REGS_9798, 859 + .duplex_reg = B53_DUPLEX_STAT_GE, 860 + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 861 + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 862 + }, 863 + { 864 + .chip_id = BCM53115_DEVICE_ID, 865 + .dev_name = "BCM53115", 866 + .vlans = 4096, 867 + .enabled_ports = 0x1f, 868 + .vta_regs = B53_VTA_REGS, 869 + .cpu_port = B53_CPU_PORT, 870 + .duplex_reg = B53_DUPLEX_STAT_GE, 871 + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 872 + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 873 + }, 874 + { 875 + .chip_id = BCM53125_DEVICE_ID, 876 + .dev_name = "BCM53125", 877 + .vlans = 4096, 878 + .enabled_ports = 0xff, 879 + .cpu_port = B53_CPU_PORT, 880 + .vta_regs = B53_VTA_REGS, 881 + .duplex_reg = B53_DUPLEX_STAT_GE, 882 + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 883 + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 884 + }, 885 + { 886 + .chip_id = BCM53128_DEVICE_ID, 887 + .dev_name = "BCM53128", 888 + .vlans = 4096, 889 + .enabled_ports = 0x1ff, 890 + .cpu_port = B53_CPU_PORT, 891 + .vta_regs = B53_VTA_REGS, 892 + .duplex_reg = B53_DUPLEX_STAT_GE, 893 + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 894 + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 895 + }, 896 + { 897 + .chip_id = BCM63XX_DEVICE_ID, 898 + .dev_name = "BCM63xx", 899 + .vlans = 4096, 900 + .enabled_ports = 0, /* pdata must provide them */ 901 + .cpu_port = B53_CPU_PORT, 902 + .vta_regs = B53_VTA_REGS_63XX, 903 + .duplex_reg = B53_DUPLEX_STAT_63XX, 904 + .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX, 905 + .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX, 906 + }, 907 + { 908 + .chip_id = BCM53010_DEVICE_ID, 909 + .dev_name = "BCM53010", 910 + .vlans = 4096, 911 + .enabled_ports = 0x1f, 912 + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ 913 + .vta_regs = B53_VTA_REGS, 914 + .duplex_reg = B53_DUPLEX_STAT_GE, 915 + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 916 + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 917 + }, 918 + { 919 + .chip_id = BCM53011_DEVICE_ID, 920 + .dev_name = "BCM53011", 921 + .vlans = 4096, 922 + .enabled_ports = 0x1bf, 923 + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ 924 + .vta_regs = B53_VTA_REGS, 925 + .duplex_reg = B53_DUPLEX_STAT_GE, 926 + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 927 + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 928 + }, 929 + { 930 + .chip_id = BCM53012_DEVICE_ID, 931 + .dev_name = "BCM53012", 932 + .vlans = 4096, 933 + .enabled_ports = 0x1bf, 934 + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ 935 + .vta_regs = B53_VTA_REGS, 936 + .duplex_reg = B53_DUPLEX_STAT_GE, 937 + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 938 + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 939 + }, 940 + { 941 + .chip_id = BCM53018_DEVICE_ID, 942 + .dev_name = "BCM53018", 943 + .vlans = 4096, 944 + .enabled_ports = 0x1f, 945 + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ 946 + .vta_regs = B53_VTA_REGS, 947 + .duplex_reg = B53_DUPLEX_STAT_GE, 948 + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 949 + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 950 + }, 951 + { 952 + .chip_id = BCM53019_DEVICE_ID, 953 + .dev_name = "BCM53019", 954 + .vlans = 4096, 955 + .enabled_ports = 0x1f, 956 + .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ 957 + .vta_regs = B53_VTA_REGS, 958 + .duplex_reg = B53_DUPLEX_STAT_GE, 959 + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 960 + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 961 + }, 962 + }; 963 + 964 + static int b53_switch_init(struct b53_device *dev) 965 + { 966 + struct dsa_switch *ds = dev->ds; 967 + unsigned int i; 968 + int ret; 969 + 970 + for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) { 971 + const struct b53_chip_data *chip = &b53_switch_chips[i]; 972 + 973 + if (chip->chip_id == dev->chip_id) { 974 + if (!dev->enabled_ports) 975 + dev->enabled_ports = chip->enabled_ports; 976 + dev->name = chip->dev_name; 977 + dev->duplex_reg = chip->duplex_reg; 978 + dev->vta_regs[0] = chip->vta_regs[0]; 979 + dev->vta_regs[1] = chip->vta_regs[1]; 980 + dev->vta_regs[2] = chip->vta_regs[2]; 981 + dev->jumbo_pm_reg = chip->jumbo_pm_reg; 982 + ds->drv = &b53_switch_ops; 983 + dev->cpu_port = chip->cpu_port; 984 + dev->num_vlans = chip->vlans; 985 + break; 986 + } 987 + } 988 + 989 + /* check which BCM5325x version we have */ 990 + if (is5325(dev)) { 991 + u8 vc4; 992 + 993 + b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4); 994 + 995 + /* check reserved bits */ 996 + switch (vc4 & 3) { 997 + case 1: 998 + /* BCM5325E */ 999 + break; 1000 + case 3: 1001 + /* BCM5325F - do not use port 4 */ 1002 + dev->enabled_ports &= ~BIT(4); 1003 + break; 1004 + default: 1005 + /* On the BCM47XX SoCs this is the supported internal switch.*/ 1006 + #ifndef CONFIG_BCM47XX 1007 + /* BCM5325M */ 1008 + return -EINVAL; 1009 + #else 1010 + break; 1011 + #endif 1012 + } 1013 + } else if (dev->chip_id == BCM53115_DEVICE_ID) { 1014 + u64 strap_value; 1015 + 1016 + b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value); 1017 + /* use second IMP port if GMII is enabled */ 1018 + if (strap_value & SV_GMII_CTRL_115) 1019 + dev->cpu_port = 5; 1020 + } 1021 + 1022 + /* cpu port is always last */ 1023 + dev->num_ports = dev->cpu_port + 1; 1024 + dev->enabled_ports |= BIT(dev->cpu_port); 1025 + 1026 + dev->ports = devm_kzalloc(dev->dev, 1027 + sizeof(struct b53_port) * dev->num_ports, 1028 + GFP_KERNEL); 1029 + if (!dev->ports) 1030 + return -ENOMEM; 1031 + 1032 + dev->reset_gpio = b53_switch_get_reset_gpio(dev); 1033 + if (dev->reset_gpio >= 0) { 1034 + ret = devm_gpio_request_one(dev->dev, dev->reset_gpio, 1035 + GPIOF_OUT_INIT_HIGH, "robo_reset"); 1036 + if (ret) 1037 + return ret; 1038 + } 1039 + 1040 + return 0; 1041 + } 1042 + 1043 + struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops, 1044 + void *priv) 1045 + { 1046 + struct dsa_switch *ds; 1047 + struct b53_device *dev; 1048 + 1049 + ds = devm_kzalloc(base, sizeof(*ds) + sizeof(*dev), GFP_KERNEL); 1050 + if (!ds) 1051 + return NULL; 1052 + 1053 + dev = (struct b53_device *)(ds + 1); 1054 + 1055 + ds->priv = dev; 1056 + ds->dev = base; 1057 + dev->dev = base; 1058 + 1059 + dev->ds = ds; 1060 + dev->priv = priv; 1061 + dev->ops = ops; 1062 + mutex_init(&dev->reg_mutex); 1063 + mutex_init(&dev->stats_mutex); 1064 + 1065 + return dev; 1066 + } 1067 + EXPORT_SYMBOL(b53_switch_alloc); 1068 + 1069 + int b53_switch_detect(struct b53_device *dev) 1070 + { 1071 + u32 id32; 1072 + u16 tmp; 1073 + u8 id8; 1074 + int ret; 1075 + 1076 + ret = b53_read8(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id8); 1077 + if (ret) 1078 + return ret; 1079 + 1080 + switch (id8) { 1081 + case 0: 1082 + /* BCM5325 and BCM5365 do not have this register so reads 1083 + * return 0. But the read operation did succeed, so assume this 1084 + * is one of them. 1085 + * 1086 + * Next check if we can write to the 5325's VTA register; for 1087 + * 5365 it is read only. 1088 + */ 1089 + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf); 1090 + b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp); 1091 + 1092 + if (tmp == 0xf) 1093 + dev->chip_id = BCM5325_DEVICE_ID; 1094 + else 1095 + dev->chip_id = BCM5365_DEVICE_ID; 1096 + break; 1097 + case BCM5395_DEVICE_ID: 1098 + case BCM5397_DEVICE_ID: 1099 + case BCM5398_DEVICE_ID: 1100 + dev->chip_id = id8; 1101 + break; 1102 + default: 1103 + ret = b53_read32(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id32); 1104 + if (ret) 1105 + return ret; 1106 + 1107 + switch (id32) { 1108 + case BCM53115_DEVICE_ID: 1109 + case BCM53125_DEVICE_ID: 1110 + case BCM53128_DEVICE_ID: 1111 + case BCM53010_DEVICE_ID: 1112 + case BCM53011_DEVICE_ID: 1113 + case BCM53012_DEVICE_ID: 1114 + case BCM53018_DEVICE_ID: 1115 + case BCM53019_DEVICE_ID: 1116 + dev->chip_id = id32; 1117 + break; 1118 + default: 1119 + pr_err("unsupported switch detected (BCM53%02x/BCM%x)\n", 1120 + id8, id32); 1121 + return -ENODEV; 1122 + } 1123 + } 1124 + 1125 + if (dev->chip_id == BCM5325_DEVICE_ID) 1126 + return b53_read8(dev, B53_STAT_PAGE, B53_REV_ID_25, 1127 + &dev->core_rev); 1128 + else 1129 + return b53_read8(dev, B53_MGMT_PAGE, B53_REV_ID, 1130 + &dev->core_rev); 1131 + } 1132 + EXPORT_SYMBOL(b53_switch_detect); 1133 + 1134 + int b53_switch_register(struct b53_device *dev) 1135 + { 1136 + int ret; 1137 + 1138 + if (dev->pdata) { 1139 + dev->chip_id = dev->pdata->chip_id; 1140 + dev->enabled_ports = dev->pdata->enabled_ports; 1141 + } 1142 + 1143 + if (!dev->chip_id && b53_switch_detect(dev)) 1144 + return -EINVAL; 1145 + 1146 + ret = b53_switch_init(dev); 1147 + if (ret) 1148 + return ret; 1149 + 1150 + pr_info("found switch: %s, rev %i\n", dev->name, dev->core_rev); 1151 + 1152 + return dsa_register_switch(dev->ds, dev->ds->dev->of_node); 1153 + } 1154 + EXPORT_SYMBOL(b53_switch_register); 1155 + 1156 + MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>"); 1157 + MODULE_DESCRIPTION("B53 switch library"); 1158 + MODULE_LICENSE("Dual BSD/GPL");
+381
drivers/net/dsa/b53/b53_mdio.c
··· 1 + /* 2 + * B53 register access through MII registers 3 + * 4 + * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org> 5 + * 6 + * Permission to use, copy, modify, and/or distribute this software for any 7 + * purpose with or without fee is hereby granted, provided that the above 8 + * copyright notice and this permission notice appear in all copies. 9 + * 10 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 + */ 18 + 19 + #include <linux/kernel.h> 20 + #include <linux/phy.h> 21 + #include <linux/module.h> 22 + #include <linux/delay.h> 23 + #include <linux/brcmphy.h> 24 + #include <linux/rtnetlink.h> 25 + #include <net/dsa.h> 26 + 27 + #include "b53_priv.h" 28 + 29 + /* MII registers */ 30 + #define REG_MII_PAGE 0x10 /* MII Page register */ 31 + #define REG_MII_ADDR 0x11 /* MII Address register */ 32 + #define REG_MII_DATA0 0x18 /* MII Data register 0 */ 33 + #define REG_MII_DATA1 0x19 /* MII Data register 1 */ 34 + #define REG_MII_DATA2 0x1a /* MII Data register 2 */ 35 + #define REG_MII_DATA3 0x1b /* MII Data register 3 */ 36 + 37 + #define REG_MII_PAGE_ENABLE BIT(0) 38 + #define REG_MII_ADDR_WRITE BIT(0) 39 + #define REG_MII_ADDR_READ BIT(1) 40 + 41 + static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op) 42 + { 43 + int i; 44 + u16 v; 45 + int ret; 46 + struct mii_bus *bus = dev->priv; 47 + 48 + if (dev->current_page != page) { 49 + /* set page number */ 50 + v = (page << 8) | REG_MII_PAGE_ENABLE; 51 + ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, 52 + REG_MII_PAGE, v); 53 + if (ret) 54 + return ret; 55 + dev->current_page = page; 56 + } 57 + 58 + /* set register address */ 59 + v = (reg << 8) | op; 60 + ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_ADDR, v); 61 + if (ret) 62 + return ret; 63 + 64 + /* check if operation completed */ 65 + for (i = 0; i < 5; ++i) { 66 + v = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, 67 + REG_MII_ADDR); 68 + if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ))) 69 + break; 70 + usleep_range(10, 100); 71 + } 72 + 73 + if (WARN_ON(i == 5)) 74 + return -EIO; 75 + 76 + return 0; 77 + } 78 + 79 + static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) 80 + { 81 + struct mii_bus *bus = dev->priv; 82 + int ret; 83 + 84 + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); 85 + if (ret) 86 + return ret; 87 + 88 + *val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, 89 + REG_MII_DATA0) & 0xff; 90 + 91 + return 0; 92 + } 93 + 94 + static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) 95 + { 96 + struct mii_bus *bus = dev->priv; 97 + int ret; 98 + 99 + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); 100 + if (ret) 101 + return ret; 102 + 103 + *val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_DATA0); 104 + 105 + return 0; 106 + } 107 + 108 + static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) 109 + { 110 + struct mii_bus *bus = dev->priv; 111 + int ret; 112 + 113 + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); 114 + if (ret) 115 + return ret; 116 + 117 + *val = mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, REG_MII_DATA0); 118 + *val |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, 119 + REG_MII_DATA1) << 16; 120 + 121 + return 0; 122 + } 123 + 124 + static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) 125 + { 126 + struct mii_bus *bus = dev->priv; 127 + u64 temp = 0; 128 + int i; 129 + int ret; 130 + 131 + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); 132 + if (ret) 133 + return ret; 134 + 135 + for (i = 2; i >= 0; i--) { 136 + temp <<= 16; 137 + temp |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, 138 + REG_MII_DATA0 + i); 139 + } 140 + 141 + *val = temp; 142 + 143 + return 0; 144 + } 145 + 146 + static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) 147 + { 148 + struct mii_bus *bus = dev->priv; 149 + u64 temp = 0; 150 + int i; 151 + int ret; 152 + 153 + ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ); 154 + if (ret) 155 + return ret; 156 + 157 + for (i = 3; i >= 0; i--) { 158 + temp <<= 16; 159 + temp |= mdiobus_read_nested(bus, BRCM_PSEUDO_PHY_ADDR, 160 + REG_MII_DATA0 + i); 161 + } 162 + 163 + *val = temp; 164 + 165 + return 0; 166 + } 167 + 168 + static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) 169 + { 170 + struct mii_bus *bus = dev->priv; 171 + int ret; 172 + 173 + ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, 174 + REG_MII_DATA0, value); 175 + if (ret) 176 + return ret; 177 + 178 + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); 179 + } 180 + 181 + static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg, 182 + u16 value) 183 + { 184 + struct mii_bus *bus = dev->priv; 185 + int ret; 186 + 187 + ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, 188 + REG_MII_DATA0, value); 189 + if (ret) 190 + return ret; 191 + 192 + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); 193 + } 194 + 195 + static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg, 196 + u32 value) 197 + { 198 + struct mii_bus *bus = dev->priv; 199 + unsigned int i; 200 + u32 temp = value; 201 + 202 + for (i = 0; i < 2; i++) { 203 + int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, 204 + REG_MII_DATA0 + i, 205 + temp & 0xffff); 206 + if (ret) 207 + return ret; 208 + temp >>= 16; 209 + } 210 + 211 + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); 212 + } 213 + 214 + static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg, 215 + u64 value) 216 + { 217 + struct mii_bus *bus = dev->priv; 218 + unsigned int i; 219 + u64 temp = value; 220 + 221 + for (i = 0; i < 3; i++) { 222 + int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, 223 + REG_MII_DATA0 + i, 224 + temp & 0xffff); 225 + if (ret) 226 + return ret; 227 + temp >>= 16; 228 + } 229 + 230 + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); 231 + } 232 + 233 + static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg, 234 + u64 value) 235 + { 236 + struct mii_bus *bus = dev->priv; 237 + unsigned int i; 238 + u64 temp = value; 239 + 240 + for (i = 0; i < 4; i++) { 241 + int ret = mdiobus_write_nested(bus, BRCM_PSEUDO_PHY_ADDR, 242 + REG_MII_DATA0 + i, 243 + temp & 0xffff); 244 + if (ret) 245 + return ret; 246 + temp >>= 16; 247 + } 248 + 249 + return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE); 250 + } 251 + 252 + static int b53_mdio_phy_read16(struct b53_device *dev, int addr, int reg, 253 + u16 *value) 254 + { 255 + struct mii_bus *bus = dev->priv; 256 + 257 + *value = mdiobus_read_nested(bus, addr, reg); 258 + 259 + return 0; 260 + } 261 + 262 + static int b53_mdio_phy_write16(struct b53_device *dev, int addr, int reg, 263 + u16 value) 264 + { 265 + struct mii_bus *bus = dev->bus; 266 + 267 + return mdiobus_write_nested(bus, addr, reg, value); 268 + } 269 + 270 + static struct b53_io_ops b53_mdio_ops = { 271 + .read8 = b53_mdio_read8, 272 + .read16 = b53_mdio_read16, 273 + .read32 = b53_mdio_read32, 274 + .read48 = b53_mdio_read48, 275 + .read64 = b53_mdio_read64, 276 + .write8 = b53_mdio_write8, 277 + .write16 = b53_mdio_write16, 278 + .write32 = b53_mdio_write32, 279 + .write48 = b53_mdio_write48, 280 + .write64 = b53_mdio_write64, 281 + .phy_read16 = b53_mdio_phy_read16, 282 + .phy_write16 = b53_mdio_phy_write16, 283 + }; 284 + 285 + #define B53_BRCM_OUI_1 0x0143bc00 286 + #define B53_BRCM_OUI_2 0x03625c00 287 + #define B53_BRCM_OUI_3 0x00406000 288 + 289 + static int b53_mdio_probe(struct mdio_device *mdiodev) 290 + { 291 + struct b53_device *dev; 292 + u32 phy_id; 293 + int ret; 294 + 295 + /* allow the generic PHY driver to take over the non-management MDIO 296 + * addresses 297 + */ 298 + if (mdiodev->addr != BRCM_PSEUDO_PHY_ADDR && mdiodev->addr != 0) { 299 + dev_err(&mdiodev->dev, "leaving address %d to PHY\n", 300 + mdiodev->addr); 301 + return -ENODEV; 302 + } 303 + 304 + /* read the first port's id */ 305 + phy_id = mdiobus_read(mdiodev->bus, 0, 2) << 16; 306 + phy_id |= mdiobus_read(mdiodev->bus, 0, 3); 307 + 308 + /* BCM5325, BCM539x (OUI_1) 309 + * BCM53125, BCM53128 (OUI_2) 310 + * BCM5365 (OUI_3) 311 + */ 312 + if ((phy_id & 0xfffffc00) != B53_BRCM_OUI_1 && 313 + (phy_id & 0xfffffc00) != B53_BRCM_OUI_2 && 314 + (phy_id & 0xfffffc00) != B53_BRCM_OUI_3) { 315 + dev_err(&mdiodev->dev, "Unsupported device: 0x%08x\n", phy_id); 316 + return -ENODEV; 317 + } 318 + 319 + dev = b53_switch_alloc(&mdiodev->dev, &b53_mdio_ops, mdiodev->bus); 320 + if (!dev) 321 + return -ENOMEM; 322 + 323 + /* we don't use page 0xff, so force a page set */ 324 + dev->current_page = 0xff; 325 + dev->bus = mdiodev->bus; 326 + 327 + dev_set_drvdata(&mdiodev->dev, dev); 328 + 329 + ret = b53_switch_register(dev); 330 + if (ret) { 331 + dev_err(&mdiodev->dev, "failed to register switch: %i\n", ret); 332 + return ret; 333 + } 334 + 335 + return ret; 336 + } 337 + 338 + static void b53_mdio_remove(struct mdio_device *mdiodev) 339 + { 340 + struct b53_device *dev = dev_get_drvdata(&mdiodev->dev); 341 + struct dsa_switch *ds = dev->ds; 342 + 343 + dsa_unregister_switch(ds); 344 + } 345 + 346 + static const struct of_device_id b53_of_match[] = { 347 + { .compatible = "brcm,bcm5325" }, 348 + { .compatible = "brcm,bcm53115" }, 349 + { .compatible = "brcm,bcm53125" }, 350 + { .compatible = "brcm,bcm53128" }, 351 + { .compatible = "brcm,bcm5365" }, 352 + { .compatible = "brcm,bcm5395" }, 353 + { .compatible = "brcm,bcm5397" }, 354 + { .compatible = "brcm,bcm5398" }, 355 + { /* sentinel */ }, 356 + }; 357 + MODULE_DEVICE_TABLE(of, b53_of_match); 358 + 359 + static struct mdio_driver b53_mdio_driver = { 360 + .probe = b53_mdio_probe, 361 + .remove = b53_mdio_remove, 362 + .mdiodrv.driver = { 363 + .name = "bcm53xx", 364 + .of_match_table = b53_of_match, 365 + }, 366 + }; 367 + 368 + static int __init b53_mdio_driver_register(void) 369 + { 370 + return mdio_driver_register(&b53_mdio_driver); 371 + } 372 + module_init(b53_mdio_driver_register); 373 + 374 + static void __exit b53_mdio_driver_unregister(void) 375 + { 376 + mdio_driver_unregister(&b53_mdio_driver); 377 + } 378 + module_exit(b53_mdio_driver_unregister); 379 + 380 + MODULE_DESCRIPTION("B53 MDIO access driver"); 381 + MODULE_LICENSE("Dual BSD/GPL");
+260
drivers/net/dsa/b53/b53_mmap.c
··· 1 + /* 2 + * B53 register access through memory mapped registers 3 + * 4 + * Copyright (C) 2012-2013 Jonas Gorski <jogo@openwrt.org> 5 + * 6 + * Permission to use, copy, modify, and/or distribute this software for any 7 + * purpose with or without fee is hereby granted, provided that the above 8 + * copyright notice and this permission notice appear in all copies. 9 + * 10 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 + */ 18 + 19 + #include <linux/kernel.h> 20 + #include <linux/kconfig.h> 21 + #include <linux/module.h> 22 + #include <linux/io.h> 23 + #include <linux/platform_device.h> 24 + #include <linux/platform_data/b53.h> 25 + 26 + #include "b53_priv.h" 27 + 28 + struct b53_mmap_priv { 29 + void __iomem *regs; 30 + }; 31 + 32 + static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) 33 + { 34 + u8 __iomem *regs = dev->priv; 35 + 36 + *val = readb(regs + (page << 8) + reg); 37 + 38 + return 0; 39 + } 40 + 41 + static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) 42 + { 43 + u8 __iomem *regs = dev->priv; 44 + 45 + if (WARN_ON(reg % 2)) 46 + return -EINVAL; 47 + 48 + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata && 49 + dev->pdata->big_endian) 50 + *val = __raw_readw(regs + (page << 8) + reg); 51 + else 52 + *val = readw(regs + (page << 8) + reg); 53 + 54 + return 0; 55 + } 56 + 57 + static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) 58 + { 59 + u8 __iomem *regs = dev->priv; 60 + 61 + if (WARN_ON(reg % 4)) 62 + return -EINVAL; 63 + 64 + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata && 65 + dev->pdata->big_endian) 66 + *val = __raw_readl(regs + (page << 8) + reg); 67 + else 68 + *val = readl(regs + (page << 8) + reg); 69 + 70 + return 0; 71 + } 72 + 73 + static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) 74 + { 75 + if (WARN_ON(reg % 2)) 76 + return -EINVAL; 77 + 78 + if (reg % 4) { 79 + u16 lo; 80 + u32 hi; 81 + 82 + b53_mmap_read16(dev, page, reg, &lo); 83 + b53_mmap_read32(dev, page, reg + 2, &hi); 84 + 85 + *val = ((u64)hi << 16) | lo; 86 + } else { 87 + u32 lo; 88 + u16 hi; 89 + 90 + b53_mmap_read32(dev, page, reg, &lo); 91 + b53_mmap_read16(dev, page, reg + 4, &hi); 92 + 93 + *val = ((u64)hi << 32) | lo; 94 + } 95 + 96 + return 0; 97 + } 98 + 99 + static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) 100 + { 101 + u32 hi, lo; 102 + 103 + if (WARN_ON(reg % 4)) 104 + return -EINVAL; 105 + 106 + b53_mmap_read32(dev, page, reg, &lo); 107 + b53_mmap_read32(dev, page, reg + 4, &hi); 108 + 109 + *val = ((u64)hi << 32) | lo; 110 + 111 + return 0; 112 + } 113 + 114 + static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) 115 + { 116 + u8 __iomem *regs = dev->priv; 117 + 118 + writeb(value, regs + (page << 8) + reg); 119 + 120 + return 0; 121 + } 122 + 123 + static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg, 124 + u16 value) 125 + { 126 + u8 __iomem *regs = dev->priv; 127 + 128 + if (WARN_ON(reg % 2)) 129 + return -EINVAL; 130 + 131 + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata && 132 + dev->pdata->big_endian) 133 + __raw_writew(value, regs + (page << 8) + reg); 134 + else 135 + writew(value, regs + (page << 8) + reg); 136 + 137 + return 0; 138 + } 139 + 140 + static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg, 141 + u32 value) 142 + { 143 + u8 __iomem *regs = dev->priv; 144 + 145 + if (WARN_ON(reg % 4)) 146 + return -EINVAL; 147 + 148 + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata && 149 + dev->pdata->big_endian) 150 + __raw_writel(value, regs + (page << 8) + reg); 151 + else 152 + writel(value, regs + (page << 8) + reg); 153 + 154 + return 0; 155 + } 156 + 157 + static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg, 158 + u64 value) 159 + { 160 + if (WARN_ON(reg % 2)) 161 + return -EINVAL; 162 + 163 + if (reg % 4) { 164 + u32 hi = (u32)(value >> 16); 165 + u16 lo = (u16)value; 166 + 167 + b53_mmap_write16(dev, page, reg, lo); 168 + b53_mmap_write32(dev, page, reg + 2, hi); 169 + } else { 170 + u16 hi = (u16)(value >> 32); 171 + u32 lo = (u32)value; 172 + 173 + b53_mmap_write32(dev, page, reg, lo); 174 + b53_mmap_write16(dev, page, reg + 4, hi); 175 + } 176 + 177 + return 0; 178 + } 179 + 180 + static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg, 181 + u64 value) 182 + { 183 + u32 hi, lo; 184 + 185 + hi = upper_32_bits(value); 186 + lo = lower_32_bits(value); 187 + 188 + if (WARN_ON(reg % 4)) 189 + return -EINVAL; 190 + 191 + b53_mmap_write32(dev, page, reg, lo); 192 + b53_mmap_write32(dev, page, reg + 4, hi); 193 + 194 + return 0; 195 + } 196 + 197 + static struct b53_io_ops b53_mmap_ops = { 198 + .read8 = b53_mmap_read8, 199 + .read16 = b53_mmap_read16, 200 + .read32 = b53_mmap_read32, 201 + .read48 = b53_mmap_read48, 202 + .read64 = b53_mmap_read64, 203 + .write8 = b53_mmap_write8, 204 + .write16 = b53_mmap_write16, 205 + .write32 = b53_mmap_write32, 206 + .write48 = b53_mmap_write48, 207 + .write64 = b53_mmap_write64, 208 + }; 209 + 210 + static int b53_mmap_probe(struct platform_device *pdev) 211 + { 212 + struct b53_platform_data *pdata = pdev->dev.platform_data; 213 + struct b53_device *dev; 214 + 215 + if (!pdata) 216 + return -EINVAL; 217 + 218 + dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs); 219 + if (!dev) 220 + return -ENOMEM; 221 + 222 + if (pdata) 223 + dev->pdata = pdata; 224 + 225 + platform_set_drvdata(pdev, dev); 226 + 227 + return b53_switch_register(dev); 228 + } 229 + 230 + static int b53_mmap_remove(struct platform_device *pdev) 231 + { 232 + struct b53_device *dev = platform_get_drvdata(pdev); 233 + 234 + if (dev) 235 + b53_switch_remove(dev); 236 + 237 + return 0; 238 + } 239 + 240 + static const struct of_device_id b53_mmap_of_table[] = { 241 + { .compatible = "brcm,bcm3384-switch" }, 242 + { .compatible = "brcm,bcm6328-switch" }, 243 + { .compatible = "brcm,bcm6368-switch" }, 244 + { .compatible = "brcm,bcm63xx-switch" }, 245 + { /* sentinel */ }, 246 + }; 247 + 248 + static struct platform_driver b53_mmap_driver = { 249 + .probe = b53_mmap_probe, 250 + .remove = b53_mmap_remove, 251 + .driver = { 252 + .name = "b53-switch", 253 + .of_match_table = b53_mmap_of_table, 254 + }, 255 + }; 256 + 257 + module_platform_driver(b53_mmap_driver); 258 + MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>"); 259 + MODULE_DESCRIPTION("B53 MMAP access driver"); 260 + MODULE_LICENSE("Dual BSD/GPL");
+322
drivers/net/dsa/b53/b53_priv.h
··· 1 + /* 2 + * B53 common definitions 3 + * 4 + * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org> 5 + * 6 + * Permission to use, copy, modify, and/or distribute this software for any 7 + * purpose with or without fee is hereby granted, provided that the above 8 + * copyright notice and this permission notice appear in all copies. 9 + * 10 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 + */ 18 + 19 + #ifndef __B53_PRIV_H 20 + #define __B53_PRIV_H 21 + 22 + #include <linux/kernel.h> 23 + #include <linux/mutex.h> 24 + #include <linux/phy.h> 25 + #include <net/dsa.h> 26 + 27 + struct b53_device; 28 + 29 + struct b53_io_ops { 30 + int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value); 31 + int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value); 32 + int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value); 33 + int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value); 34 + int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value); 35 + int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value); 36 + int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value); 37 + int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value); 38 + int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value); 39 + int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value); 40 + int (*phy_read16)(struct b53_device *dev, int addr, int reg, u16 *value); 41 + int (*phy_write16)(struct b53_device *dev, int addr, int reg, u16 value); 42 + }; 43 + 44 + enum { 45 + BCM5325_DEVICE_ID = 0x25, 46 + BCM5365_DEVICE_ID = 0x65, 47 + BCM5395_DEVICE_ID = 0x95, 48 + BCM5397_DEVICE_ID = 0x97, 49 + BCM5398_DEVICE_ID = 0x98, 50 + BCM53115_DEVICE_ID = 0x53115, 51 + BCM53125_DEVICE_ID = 0x53125, 52 + BCM53128_DEVICE_ID = 0x53128, 53 + BCM63XX_DEVICE_ID = 0x6300, 54 + BCM53010_DEVICE_ID = 0x53010, 55 + BCM53011_DEVICE_ID = 0x53011, 56 + BCM53012_DEVICE_ID = 0x53012, 57 + BCM53018_DEVICE_ID = 0x53018, 58 + BCM53019_DEVICE_ID = 0x53019, 59 + }; 60 + 61 + #define B53_N_PORTS 9 62 + #define B53_N_PORTS_25 6 63 + 64 + struct b53_port { 65 + }; 66 + 67 + struct b53_device { 68 + struct dsa_switch *ds; 69 + struct b53_platform_data *pdata; 70 + const char *name; 71 + 72 + struct mutex reg_mutex; 73 + struct mutex stats_mutex; 74 + const struct b53_io_ops *ops; 75 + 76 + /* chip specific data */ 77 + u32 chip_id; 78 + u8 core_rev; 79 + u8 vta_regs[3]; 80 + u8 duplex_reg; 81 + u8 jumbo_pm_reg; 82 + u8 jumbo_size_reg; 83 + int reset_gpio; 84 + 85 + /* used ports mask */ 86 + u16 enabled_ports; 87 + unsigned int cpu_port; 88 + 89 + /* connect specific data */ 90 + u8 current_page; 91 + struct device *dev; 92 + 93 + /* Master MDIO bus we got probed from */ 94 + struct mii_bus *bus; 95 + 96 + /* Slave MDIO bus we created */ 97 + struct mii_bus *slave_bus; 98 + void *priv; 99 + 100 + /* run time configuration */ 101 + unsigned enable_jumbo:1; 102 + unsigned allow_vid_4095:1; 103 + unsigned int num_vlans; 104 + unsigned int num_ports; 105 + struct b53_port *ports; 106 + }; 107 + 108 + #define b53_for_each_port(dev, i) \ 109 + for (i = 0; i < B53_N_PORTS; i++) \ 110 + if (dev->enabled_ports & BIT(i)) 111 + 112 + 113 + static inline int is5325(struct b53_device *dev) 114 + { 115 + return dev->chip_id == BCM5325_DEVICE_ID; 116 + } 117 + 118 + static inline int is5365(struct b53_device *dev) 119 + { 120 + #ifdef CONFIG_BCM47XX 121 + return dev->chip_id == BCM5365_DEVICE_ID; 122 + #else 123 + return 0; 124 + #endif 125 + } 126 + 127 + static inline int is5397_98(struct b53_device *dev) 128 + { 129 + return dev->chip_id == BCM5397_DEVICE_ID || 130 + dev->chip_id == BCM5398_DEVICE_ID; 131 + } 132 + 133 + static inline int is539x(struct b53_device *dev) 134 + { 135 + return dev->chip_id == BCM5395_DEVICE_ID || 136 + dev->chip_id == BCM5397_DEVICE_ID || 137 + dev->chip_id == BCM5398_DEVICE_ID; 138 + } 139 + 140 + static inline int is531x5(struct b53_device *dev) 141 + { 142 + return dev->chip_id == BCM53115_DEVICE_ID || 143 + dev->chip_id == BCM53125_DEVICE_ID || 144 + dev->chip_id == BCM53128_DEVICE_ID; 145 + } 146 + 147 + static inline int is63xx(struct b53_device *dev) 148 + { 149 + #ifdef CONFIG_BCM63XX 150 + return dev->chip_id == BCM63XX_DEVICE_ID; 151 + #else 152 + return 0; 153 + #endif 154 + } 155 + 156 + static inline int is5301x(struct b53_device *dev) 157 + { 158 + return dev->chip_id == BCM53010_DEVICE_ID || 159 + dev->chip_id == BCM53011_DEVICE_ID || 160 + dev->chip_id == BCM53012_DEVICE_ID || 161 + dev->chip_id == BCM53018_DEVICE_ID || 162 + dev->chip_id == BCM53019_DEVICE_ID; 163 + } 164 + 165 + #define B53_CPU_PORT_25 5 166 + #define B53_CPU_PORT 8 167 + 168 + static inline int is_cpu_port(struct b53_device *dev, int port) 169 + { 170 + return dev->cpu_port; 171 + } 172 + 173 + struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops, 174 + void *priv); 175 + 176 + int b53_switch_detect(struct b53_device *dev); 177 + 178 + int b53_switch_register(struct b53_device *dev); 179 + 180 + static inline void b53_switch_remove(struct b53_device *dev) 181 + { 182 + dsa_unregister_switch(dev->ds); 183 + } 184 + 185 + static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) 186 + { 187 + int ret; 188 + 189 + mutex_lock(&dev->reg_mutex); 190 + ret = dev->ops->read8(dev, page, reg, val); 191 + mutex_unlock(&dev->reg_mutex); 192 + 193 + return ret; 194 + } 195 + 196 + static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) 197 + { 198 + int ret; 199 + 200 + mutex_lock(&dev->reg_mutex); 201 + ret = dev->ops->read16(dev, page, reg, val); 202 + mutex_unlock(&dev->reg_mutex); 203 + 204 + return ret; 205 + } 206 + 207 + static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) 208 + { 209 + int ret; 210 + 211 + mutex_lock(&dev->reg_mutex); 212 + ret = dev->ops->read32(dev, page, reg, val); 213 + mutex_unlock(&dev->reg_mutex); 214 + 215 + return ret; 216 + } 217 + 218 + static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) 219 + { 220 + int ret; 221 + 222 + mutex_lock(&dev->reg_mutex); 223 + ret = dev->ops->read48(dev, page, reg, val); 224 + mutex_unlock(&dev->reg_mutex); 225 + 226 + return ret; 227 + } 228 + 229 + static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) 230 + { 231 + int ret; 232 + 233 + mutex_lock(&dev->reg_mutex); 234 + ret = dev->ops->read64(dev, page, reg, val); 235 + mutex_unlock(&dev->reg_mutex); 236 + 237 + return ret; 238 + } 239 + 240 + static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) 241 + { 242 + int ret; 243 + 244 + mutex_lock(&dev->reg_mutex); 245 + ret = dev->ops->write8(dev, page, reg, value); 246 + mutex_unlock(&dev->reg_mutex); 247 + 248 + return ret; 249 + } 250 + 251 + static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg, 252 + u16 value) 253 + { 254 + int ret; 255 + 256 + mutex_lock(&dev->reg_mutex); 257 + ret = dev->ops->write16(dev, page, reg, value); 258 + mutex_unlock(&dev->reg_mutex); 259 + 260 + return ret; 261 + } 262 + 263 + static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg, 264 + u32 value) 265 + { 266 + int ret; 267 + 268 + mutex_lock(&dev->reg_mutex); 269 + ret = dev->ops->write32(dev, page, reg, value); 270 + mutex_unlock(&dev->reg_mutex); 271 + 272 + return ret; 273 + } 274 + 275 + static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg, 276 + u64 value) 277 + { 278 + int ret; 279 + 280 + mutex_lock(&dev->reg_mutex); 281 + ret = dev->ops->write48(dev, page, reg, value); 282 + mutex_unlock(&dev->reg_mutex); 283 + 284 + return ret; 285 + } 286 + 287 + static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg, 288 + u64 value) 289 + { 290 + int ret; 291 + 292 + mutex_lock(&dev->reg_mutex); 293 + ret = dev->ops->write64(dev, page, reg, value); 294 + mutex_unlock(&dev->reg_mutex); 295 + 296 + return ret; 297 + } 298 + 299 + #ifdef CONFIG_BCM47XX 300 + 301 + #include <linux/version.h> 302 + #include <linux/bcm47xx_nvram.h> 303 + #include <bcm47xx_board.h> 304 + static inline int b53_switch_get_reset_gpio(struct b53_device *dev) 305 + { 306 + enum bcm47xx_board board = bcm47xx_board_get(); 307 + 308 + switch (board) { 309 + case BCM47XX_BOARD_LINKSYS_WRT300NV11: 310 + case BCM47XX_BOARD_LINKSYS_WRT310NV1: 311 + return 8; 312 + default: 313 + return bcm47xx_nvram_gpio_pin("robo_reset"); 314 + } 315 + } 316 + #else 317 + static inline int b53_switch_get_reset_gpio(struct b53_device *dev) 318 + { 319 + return -ENOENT; 320 + } 321 + #endif 322 + #endif
+358
drivers/net/dsa/b53/b53_regs.h
··· 1 + /* 2 + * B53 register definitions 3 + * 4 + * Copyright (C) 2004 Broadcom Corporation 5 + * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org> 6 + * 7 + * Permission to use, copy, modify, and/or distribute this software for any 8 + * purpose with or without fee is hereby granted, provided that the above 9 + * copyright notice and this permission notice appear in all copies. 10 + * 11 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 + */ 19 + 20 + #ifndef __B53_REGS_H 21 + #define __B53_REGS_H 22 + 23 + /* Management Port (SMP) Page offsets */ 24 + #define B53_CTRL_PAGE 0x00 /* Control */ 25 + #define B53_STAT_PAGE 0x01 /* Status */ 26 + #define B53_MGMT_PAGE 0x02 /* Management Mode */ 27 + #define B53_MIB_AC_PAGE 0x03 /* MIB Autocast */ 28 + #define B53_ARLCTRL_PAGE 0x04 /* ARL Control */ 29 + #define B53_ARLIO_PAGE 0x05 /* ARL Access */ 30 + #define B53_FRAMEBUF_PAGE 0x06 /* Management frame access */ 31 + #define B53_MEM_ACCESS_PAGE 0x08 /* Memory access */ 32 + 33 + /* PHY Registers */ 34 + #define B53_PORT_MII_PAGE(i) (0x10 + (i)) /* Port i MII Registers */ 35 + #define B53_IM_PORT_PAGE 0x18 /* Inverse MII Port (to EMAC) */ 36 + #define B53_ALL_PORT_PAGE 0x19 /* All ports MII (broadcast) */ 37 + 38 + /* MIB registers */ 39 + #define B53_MIB_PAGE(i) (0x20 + (i)) 40 + 41 + /* Quality of Service (QoS) Registers */ 42 + #define B53_QOS_PAGE 0x30 43 + 44 + /* Port VLAN Page */ 45 + #define B53_PVLAN_PAGE 0x31 46 + 47 + /* VLAN Registers */ 48 + #define B53_VLAN_PAGE 0x34 49 + 50 + /* Jumbo Frame Registers */ 51 + #define B53_JUMBO_PAGE 0x40 52 + 53 + /* CFP Configuration Registers Page */ 54 + #define B53_CFP_PAGE 0xa1 55 + 56 + /************************************************************************* 57 + * Control Page registers 58 + *************************************************************************/ 59 + 60 + /* Port Control Register (8 bit) */ 61 + #define B53_PORT_CTRL(i) (0x00 + (i)) 62 + #define PORT_CTRL_RX_DISABLE BIT(0) 63 + #define PORT_CTRL_TX_DISABLE BIT(1) 64 + #define PORT_CTRL_RX_BCST_EN BIT(2) /* Broadcast RX (P8 only) */ 65 + #define PORT_CTRL_RX_MCST_EN BIT(3) /* Multicast RX (P8 only) */ 66 + #define PORT_CTRL_RX_UCST_EN BIT(4) /* Unicast RX (P8 only) */ 67 + #define PORT_CTRL_STP_STATE_S 5 68 + #define PORT_CTRL_STP_STATE_MASK (0x7 << PORT_CTRL_STP_STATE_S) 69 + 70 + /* SMP Control Register (8 bit) */ 71 + #define B53_SMP_CTRL 0x0a 72 + 73 + /* Switch Mode Control Register (8 bit) */ 74 + #define B53_SWITCH_MODE 0x0b 75 + #define SM_SW_FWD_MODE BIT(0) /* 1 = Managed Mode */ 76 + #define SM_SW_FWD_EN BIT(1) /* Forwarding Enable */ 77 + 78 + /* IMP Port state override register (8 bit) */ 79 + #define B53_PORT_OVERRIDE_CTRL 0x0e 80 + #define PORT_OVERRIDE_LINK BIT(0) 81 + #define PORT_OVERRIDE_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */ 82 + #define PORT_OVERRIDE_SPEED_S 2 83 + #define PORT_OVERRIDE_SPEED_10M (0 << PORT_OVERRIDE_SPEED_S) 84 + #define PORT_OVERRIDE_SPEED_100M (1 << PORT_OVERRIDE_SPEED_S) 85 + #define PORT_OVERRIDE_SPEED_1000M (2 << PORT_OVERRIDE_SPEED_S) 86 + #define PORT_OVERRIDE_RV_MII_25 BIT(4) /* BCM5325 only */ 87 + #define PORT_OVERRIDE_RX_FLOW BIT(4) 88 + #define PORT_OVERRIDE_TX_FLOW BIT(5) 89 + #define PORT_OVERRIDE_SPEED_2000M BIT(6) /* BCM5301X only, requires setting 1000M */ 90 + #define PORT_OVERRIDE_EN BIT(7) /* Use the register contents */ 91 + 92 + /* Power-down mode control */ 93 + #define B53_PD_MODE_CTRL_25 0x0f 94 + 95 + /* IP Multicast control (8 bit) */ 96 + #define B53_IP_MULTICAST_CTRL 0x21 97 + #define B53_IPMC_FWD_EN BIT(1) 98 + #define B53_UC_FWD_EN BIT(6) 99 + #define B53_MC_FWD_EN BIT(7) 100 + 101 + /* (16 bit) */ 102 + #define B53_UC_FLOOD_MASK 0x32 103 + #define B53_MC_FLOOD_MASK 0x34 104 + #define B53_IPMC_FLOOD_MASK 0x36 105 + 106 + /* 107 + * Override Ports 0-7 State on devices with xMII interfaces (8 bit) 108 + * 109 + * For port 8 still use B53_PORT_OVERRIDE_CTRL 110 + * Please note that not all ports are available on every hardware, e.g. BCM5301X 111 + * don't include overriding port 6, BCM63xx also have some limitations. 112 + */ 113 + #define B53_GMII_PORT_OVERRIDE_CTRL(i) (0x58 + (i)) 114 + #define GMII_PO_LINK BIT(0) 115 + #define GMII_PO_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */ 116 + #define GMII_PO_SPEED_S 2 117 + #define GMII_PO_SPEED_10M (0 << GMII_PO_SPEED_S) 118 + #define GMII_PO_SPEED_100M (1 << GMII_PO_SPEED_S) 119 + #define GMII_PO_SPEED_1000M (2 << GMII_PO_SPEED_S) 120 + #define GMII_PO_RX_FLOW BIT(4) 121 + #define GMII_PO_TX_FLOW BIT(5) 122 + #define GMII_PO_EN BIT(6) /* Use the register contents */ 123 + #define GMII_PO_SPEED_2000M BIT(7) /* BCM5301X only, requires setting 1000M */ 124 + 125 + #define B53_RGMII_CTRL_IMP 0x60 126 + #define RGMII_CTRL_ENABLE_GMII BIT(7) 127 + #define RGMII_CTRL_TIMING_SEL BIT(2) 128 + #define RGMII_CTRL_DLL_RXC BIT(1) 129 + #define RGMII_CTRL_DLL_TXC BIT(0) 130 + 131 + #define B53_RGMII_CTRL_P(i) (B53_RGMII_CTRL_IMP + (i)) 132 + 133 + /* Software reset register (8 bit) */ 134 + #define B53_SOFTRESET 0x79 135 + #define SW_RST BIT(7) 136 + #define EN_SW_RST BIT(4) 137 + 138 + /* Fast Aging Control register (8 bit) */ 139 + #define B53_FAST_AGE_CTRL 0x88 140 + #define FAST_AGE_STATIC BIT(0) 141 + #define FAST_AGE_DYNAMIC BIT(1) 142 + #define FAST_AGE_PORT BIT(2) 143 + #define FAST_AGE_VLAN BIT(3) 144 + #define FAST_AGE_STP BIT(4) 145 + #define FAST_AGE_MC BIT(5) 146 + #define FAST_AGE_DONE BIT(7) 147 + 148 + /************************************************************************* 149 + * Status Page registers 150 + *************************************************************************/ 151 + 152 + /* Link Status Summary Register (16bit) */ 153 + #define B53_LINK_STAT 0x00 154 + 155 + /* Link Status Change Register (16 bit) */ 156 + #define B53_LINK_STAT_CHANGE 0x02 157 + 158 + /* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */ 159 + #define B53_SPEED_STAT 0x04 160 + #define SPEED_PORT_FE(reg, port) (((reg) >> (port)) & 1) 161 + #define SPEED_PORT_GE(reg, port) (((reg) >> 2 * (port)) & 3) 162 + #define SPEED_STAT_10M 0 163 + #define SPEED_STAT_100M 1 164 + #define SPEED_STAT_1000M 2 165 + 166 + /* Duplex Status Summary (16 bit) */ 167 + #define B53_DUPLEX_STAT_FE 0x06 168 + #define B53_DUPLEX_STAT_GE 0x08 169 + #define B53_DUPLEX_STAT_63XX 0x0c 170 + 171 + /* Revision ID register for BCM5325 */ 172 + #define B53_REV_ID_25 0x50 173 + 174 + /* Strap Value (48 bit) */ 175 + #define B53_STRAP_VALUE 0x70 176 + #define SV_GMII_CTRL_115 BIT(27) 177 + 178 + /************************************************************************* 179 + * Management Mode Page Registers 180 + *************************************************************************/ 181 + 182 + /* Global Management Config Register (8 bit) */ 183 + #define B53_GLOBAL_CONFIG 0x00 184 + #define GC_RESET_MIB 0x01 185 + #define GC_RX_BPDU_EN 0x02 186 + #define GC_MIB_AC_HDR_EN 0x10 187 + #define GC_MIB_AC_EN 0x20 188 + #define GC_FRM_MGMT_PORT_M 0xC0 189 + #define GC_FRM_MGMT_PORT_04 0x00 190 + #define GC_FRM_MGMT_PORT_MII 0x80 191 + 192 + /* Broadcom Header control register (8 bit) */ 193 + #define B53_BRCM_HDR 0x03 194 + #define BRCM_HDR_P8_EN BIT(0) /* Enable tagging on port 8 */ 195 + #define BRCM_HDR_P5_EN BIT(1) /* Enable tagging on port 5 */ 196 + 197 + /* Device ID register (8 or 32 bit) */ 198 + #define B53_DEVICE_ID 0x30 199 + 200 + /* Revision ID register (8 bit) */ 201 + #define B53_REV_ID 0x40 202 + 203 + /************************************************************************* 204 + * ARL Access Page Registers 205 + *************************************************************************/ 206 + 207 + /* VLAN Table Access Register (8 bit) */ 208 + #define B53_VT_ACCESS 0x80 209 + #define B53_VT_ACCESS_9798 0x60 /* for BCM5397/BCM5398 */ 210 + #define B53_VT_ACCESS_63XX 0x60 /* for BCM6328/62/68 */ 211 + #define VTA_CMD_WRITE 0 212 + #define VTA_CMD_READ 1 213 + #define VTA_CMD_CLEAR 2 214 + #define VTA_START_CMD BIT(7) 215 + 216 + /* VLAN Table Index Register (16 bit) */ 217 + #define B53_VT_INDEX 0x81 218 + #define B53_VT_INDEX_9798 0x61 219 + #define B53_VT_INDEX_63XX 0x62 220 + 221 + /* VLAN Table Entry Register (32 bit) */ 222 + #define B53_VT_ENTRY 0x83 223 + #define B53_VT_ENTRY_9798 0x63 224 + #define B53_VT_ENTRY_63XX 0x64 225 + #define VTE_MEMBERS 0x1ff 226 + #define VTE_UNTAG_S 9 227 + #define VTE_UNTAG (0x1ff << 9) 228 + 229 + /************************************************************************* 230 + * Port VLAN Registers 231 + *************************************************************************/ 232 + 233 + /* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */ 234 + #define B53_PVLAN_PORT_MASK(i) ((i) * 2) 235 + 236 + /************************************************************************* 237 + * 802.1Q Page Registers 238 + *************************************************************************/ 239 + 240 + /* Global QoS Control (8 bit) */ 241 + #define B53_QOS_GLOBAL_CTL 0x00 242 + 243 + /* Enable 802.1Q for individual Ports (16 bit) */ 244 + #define B53_802_1P_EN 0x04 245 + 246 + /************************************************************************* 247 + * VLAN Page Registers 248 + *************************************************************************/ 249 + 250 + /* VLAN Control 0 (8 bit) */ 251 + #define B53_VLAN_CTRL0 0x00 252 + #define VC0_8021PF_CTRL_MASK 0x3 253 + #define VC0_8021PF_CTRL_NONE 0x0 254 + #define VC0_8021PF_CTRL_CHANGE_PRI 0x1 255 + #define VC0_8021PF_CTRL_CHANGE_VID 0x2 256 + #define VC0_8021PF_CTRL_CHANGE_BOTH 0x3 257 + #define VC0_8021QF_CTRL_MASK 0xc 258 + #define VC0_8021QF_CTRL_CHANGE_PRI 0x1 259 + #define VC0_8021QF_CTRL_CHANGE_VID 0x2 260 + #define VC0_8021QF_CTRL_CHANGE_BOTH 0x3 261 + #define VC0_RESERVED_1 BIT(1) 262 + #define VC0_DROP_VID_MISS BIT(4) 263 + #define VC0_VID_HASH_VID BIT(5) 264 + #define VC0_VID_CHK_EN BIT(6) /* Use VID,DA or VID,SA */ 265 + #define VC0_VLAN_EN BIT(7) /* 802.1Q VLAN Enabled */ 266 + 267 + /* VLAN Control 1 (8 bit) */ 268 + #define B53_VLAN_CTRL1 0x01 269 + #define VC1_RX_MCST_TAG_EN BIT(1) 270 + #define VC1_RX_MCST_FWD_EN BIT(2) 271 + #define VC1_RX_MCST_UNTAG_EN BIT(3) 272 + 273 + /* VLAN Control 2 (8 bit) */ 274 + #define B53_VLAN_CTRL2 0x02 275 + 276 + /* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */ 277 + #define B53_VLAN_CTRL3 0x03 278 + #define B53_VLAN_CTRL3_63XX 0x04 279 + #define VC3_MAXSIZE_1532 BIT(6) /* 5325 only */ 280 + #define VC3_HIGH_8BIT_EN BIT(7) /* 5325 only */ 281 + 282 + /* VLAN Control 4 (8 bit) */ 283 + #define B53_VLAN_CTRL4 0x05 284 + #define B53_VLAN_CTRL4_25 0x04 285 + #define B53_VLAN_CTRL4_63XX 0x06 286 + #define VC4_ING_VID_CHECK_S 6 287 + #define VC4_ING_VID_CHECK_MASK (0x3 << VC4_ING_VID_CHECK_S) 288 + #define VC4_ING_VID_VIO_FWD 0 /* forward, but do not learn */ 289 + #define VC4_ING_VID_VIO_DROP 1 /* drop VID violations */ 290 + #define VC4_NO_ING_VID_CHK 2 /* do not check */ 291 + #define VC4_ING_VID_VIO_TO_IMP 3 /* redirect to MII port */ 292 + 293 + /* VLAN Control 5 (8 bit) */ 294 + #define B53_VLAN_CTRL5 0x06 295 + #define B53_VLAN_CTRL5_25 0x05 296 + #define B53_VLAN_CTRL5_63XX 0x07 297 + #define VC5_VID_FFF_EN BIT(2) 298 + #define VC5_DROP_VTABLE_MISS BIT(3) 299 + 300 + /* VLAN Control 6 (8 bit) */ 301 + #define B53_VLAN_CTRL6 0x07 302 + #define B53_VLAN_CTRL6_63XX 0x08 303 + 304 + /* VLAN Table Access Register (16 bit) */ 305 + #define B53_VLAN_TABLE_ACCESS_25 0x06 /* BCM5325E/5350 */ 306 + #define B53_VLAN_TABLE_ACCESS_65 0x08 /* BCM5365 */ 307 + #define VTA_VID_LOW_MASK_25 0xf 308 + #define VTA_VID_LOW_MASK_65 0xff 309 + #define VTA_VID_HIGH_S_25 4 310 + #define VTA_VID_HIGH_S_65 8 311 + #define VTA_VID_HIGH_MASK_25 (0xff << VTA_VID_HIGH_S_25E) 312 + #define VTA_VID_HIGH_MASK_65 (0xf << VTA_VID_HIGH_S_65) 313 + #define VTA_RW_STATE BIT(12) 314 + #define VTA_RW_STATE_RD 0 315 + #define VTA_RW_STATE_WR BIT(12) 316 + #define VTA_RW_OP_EN BIT(13) 317 + 318 + /* VLAN Read/Write Registers for (16/32 bit) */ 319 + #define B53_VLAN_WRITE_25 0x08 320 + #define B53_VLAN_WRITE_65 0x0a 321 + #define B53_VLAN_READ 0x0c 322 + #define VA_MEMBER_MASK 0x3f 323 + #define VA_UNTAG_S_25 6 324 + #define VA_UNTAG_MASK_25 0x3f 325 + #define VA_UNTAG_S_65 7 326 + #define VA_UNTAG_MASK_65 0x1f 327 + #define VA_VID_HIGH_S 12 328 + #define VA_VID_HIGH_MASK (0xffff << VA_VID_HIGH_S) 329 + #define VA_VALID_25 BIT(20) 330 + #define VA_VALID_25_R4 BIT(24) 331 + #define VA_VALID_65 BIT(14) 332 + 333 + /* VLAN Port Default Tag (16 bit) */ 334 + #define B53_VLAN_PORT_DEF_TAG(i) (0x10 + 2 * (i)) 335 + 336 + /************************************************************************* 337 + * Jumbo Frame Page Registers 338 + *************************************************************************/ 339 + 340 + /* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */ 341 + #define B53_JUMBO_PORT_MASK 0x01 342 + #define B53_JUMBO_PORT_MASK_63XX 0x04 343 + #define JPM_10_100_JUMBO_EN BIT(24) /* GigE always enabled */ 344 + 345 + /* Good Frame Max Size without 802.1Q TAG (16 bit) */ 346 + #define B53_JUMBO_MAX_SIZE 0x05 347 + #define B53_JUMBO_MAX_SIZE_63XX 0x08 348 + #define JMS_MIN_SIZE 1518 349 + #define JMS_MAX_SIZE 9724 350 + 351 + /************************************************************************* 352 + * CFP Configuration Page Registers 353 + *************************************************************************/ 354 + 355 + /* CFP Control Register with ports map (8 bit) */ 356 + #define B53_CFP_CTRL 0x00 357 + 358 + #endif /* !__B53_REGS_H */
+331
drivers/net/dsa/b53/b53_spi.c
··· 1 + /* 2 + * B53 register access through SPI 3 + * 4 + * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org> 5 + * 6 + * Permission to use, copy, modify, and/or distribute this software for any 7 + * purpose with or without fee is hereby granted, provided that the above 8 + * copyright notice and this permission notice appear in all copies. 9 + * 10 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 + */ 18 + 19 + #include <asm/unaligned.h> 20 + 21 + #include <linux/delay.h> 22 + #include <linux/kernel.h> 23 + #include <linux/module.h> 24 + #include <linux/spi/spi.h> 25 + #include <linux/platform_data/b53.h> 26 + 27 + #include "b53_priv.h" 28 + 29 + #define B53_SPI_DATA 0xf0 30 + 31 + #define B53_SPI_STATUS 0xfe 32 + #define B53_SPI_CMD_SPIF BIT(7) 33 + #define B53_SPI_CMD_RACK BIT(5) 34 + 35 + #define B53_SPI_CMD_READ 0x00 36 + #define B53_SPI_CMD_WRITE 0x01 37 + #define B53_SPI_CMD_NORMAL 0x60 38 + #define B53_SPI_CMD_FAST 0x10 39 + 40 + #define B53_SPI_PAGE_SELECT 0xff 41 + 42 + static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val, 43 + unsigned int len) 44 + { 45 + u8 txbuf[2]; 46 + 47 + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ; 48 + txbuf[1] = reg; 49 + 50 + return spi_write_then_read(spi, txbuf, 2, val, len); 51 + } 52 + 53 + static inline int b53_spi_clear_status(struct spi_device *spi) 54 + { 55 + unsigned int i; 56 + u8 rxbuf; 57 + int ret; 58 + 59 + for (i = 0; i < 10; i++) { 60 + ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1); 61 + if (ret) 62 + return ret; 63 + 64 + if (!(rxbuf & B53_SPI_CMD_SPIF)) 65 + break; 66 + 67 + mdelay(1); 68 + } 69 + 70 + if (i == 10) 71 + return -EIO; 72 + 73 + return 0; 74 + } 75 + 76 + static inline int b53_spi_set_page(struct spi_device *spi, u8 page) 77 + { 78 + u8 txbuf[3]; 79 + 80 + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; 81 + txbuf[1] = B53_SPI_PAGE_SELECT; 82 + txbuf[2] = page; 83 + 84 + return spi_write(spi, txbuf, sizeof(txbuf)); 85 + } 86 + 87 + static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page) 88 + { 89 + int ret = b53_spi_clear_status(spi); 90 + 91 + if (ret) 92 + return ret; 93 + 94 + return b53_spi_set_page(spi, page); 95 + } 96 + 97 + static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg) 98 + { 99 + u8 rxbuf; 100 + int retry_count; 101 + int ret; 102 + 103 + ret = b53_spi_read_reg(spi, reg, &rxbuf, 1); 104 + if (ret) 105 + return ret; 106 + 107 + for (retry_count = 0; retry_count < 10; retry_count++) { 108 + ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1); 109 + if (ret) 110 + return ret; 111 + 112 + if (rxbuf & B53_SPI_CMD_RACK) 113 + break; 114 + 115 + mdelay(1); 116 + } 117 + 118 + if (retry_count == 10) 119 + return -EIO; 120 + 121 + return 0; 122 + } 123 + 124 + static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data, 125 + unsigned int len) 126 + { 127 + struct spi_device *spi = dev->priv; 128 + int ret; 129 + 130 + ret = b53_prepare_reg_access(spi, page); 131 + if (ret) 132 + return ret; 133 + 134 + ret = b53_spi_prepare_reg_read(spi, reg); 135 + if (ret) 136 + return ret; 137 + 138 + return b53_spi_read_reg(spi, B53_SPI_DATA, data, len); 139 + } 140 + 141 + static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) 142 + { 143 + return b53_spi_read(dev, page, reg, val, 1); 144 + } 145 + 146 + static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) 147 + { 148 + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2); 149 + 150 + if (!ret) 151 + *val = le16_to_cpu(*val); 152 + 153 + return ret; 154 + } 155 + 156 + static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) 157 + { 158 + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4); 159 + 160 + if (!ret) 161 + *val = le32_to_cpu(*val); 162 + 163 + return ret; 164 + } 165 + 166 + static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) 167 + { 168 + int ret; 169 + 170 + *val = 0; 171 + ret = b53_spi_read(dev, page, reg, (u8 *)val, 6); 172 + if (!ret) 173 + *val = le64_to_cpu(*val); 174 + 175 + return ret; 176 + } 177 + 178 + static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) 179 + { 180 + int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8); 181 + 182 + if (!ret) 183 + *val = le64_to_cpu(*val); 184 + 185 + return ret; 186 + } 187 + 188 + static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) 189 + { 190 + struct spi_device *spi = dev->priv; 191 + int ret; 192 + u8 txbuf[3]; 193 + 194 + ret = b53_prepare_reg_access(spi, page); 195 + if (ret) 196 + return ret; 197 + 198 + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; 199 + txbuf[1] = reg; 200 + txbuf[2] = value; 201 + 202 + return spi_write(spi, txbuf, sizeof(txbuf)); 203 + } 204 + 205 + static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value) 206 + { 207 + struct spi_device *spi = dev->priv; 208 + int ret; 209 + u8 txbuf[4]; 210 + 211 + ret = b53_prepare_reg_access(spi, page); 212 + if (ret) 213 + return ret; 214 + 215 + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; 216 + txbuf[1] = reg; 217 + put_unaligned_le16(value, &txbuf[2]); 218 + 219 + return spi_write(spi, txbuf, sizeof(txbuf)); 220 + } 221 + 222 + static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value) 223 + { 224 + struct spi_device *spi = dev->priv; 225 + int ret; 226 + u8 txbuf[6]; 227 + 228 + ret = b53_prepare_reg_access(spi, page); 229 + if (ret) 230 + return ret; 231 + 232 + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; 233 + txbuf[1] = reg; 234 + put_unaligned_le32(value, &txbuf[2]); 235 + 236 + return spi_write(spi, txbuf, sizeof(txbuf)); 237 + } 238 + 239 + static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value) 240 + { 241 + struct spi_device *spi = dev->priv; 242 + int ret; 243 + u8 txbuf[10]; 244 + 245 + ret = b53_prepare_reg_access(spi, page); 246 + if (ret) 247 + return ret; 248 + 249 + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; 250 + txbuf[1] = reg; 251 + put_unaligned_le64(value, &txbuf[2]); 252 + 253 + return spi_write(spi, txbuf, sizeof(txbuf) - 2); 254 + } 255 + 256 + static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value) 257 + { 258 + struct spi_device *spi = dev->priv; 259 + int ret; 260 + u8 txbuf[10]; 261 + 262 + ret = b53_prepare_reg_access(spi, page); 263 + if (ret) 264 + return ret; 265 + 266 + txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE; 267 + txbuf[1] = reg; 268 + put_unaligned_le64(value, &txbuf[2]); 269 + 270 + return spi_write(spi, txbuf, sizeof(txbuf)); 271 + } 272 + 273 + static struct b53_io_ops b53_spi_ops = { 274 + .read8 = b53_spi_read8, 275 + .read16 = b53_spi_read16, 276 + .read32 = b53_spi_read32, 277 + .read48 = b53_spi_read48, 278 + .read64 = b53_spi_read64, 279 + .write8 = b53_spi_write8, 280 + .write16 = b53_spi_write16, 281 + .write32 = b53_spi_write32, 282 + .write48 = b53_spi_write48, 283 + .write64 = b53_spi_write64, 284 + }; 285 + 286 + static int b53_spi_probe(struct spi_device *spi) 287 + { 288 + struct b53_device *dev; 289 + int ret; 290 + 291 + dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi); 292 + if (!dev) 293 + return -ENOMEM; 294 + 295 + if (spi->dev.platform_data) 296 + dev->pdata = spi->dev.platform_data; 297 + 298 + ret = b53_switch_register(dev); 299 + if (ret) 300 + return ret; 301 + 302 + spi_set_drvdata(spi, dev); 303 + 304 + return 0; 305 + } 306 + 307 + static int b53_spi_remove(struct spi_device *spi) 308 + { 309 + struct b53_device *dev = spi_get_drvdata(spi); 310 + 311 + if (dev) 312 + b53_switch_remove(dev); 313 + 314 + return 0; 315 + } 316 + 317 + static struct spi_driver b53_spi_driver = { 318 + .driver = { 319 + .name = "b53-switch", 320 + .bus = &spi_bus_type, 321 + .owner = THIS_MODULE, 322 + }, 323 + .probe = b53_spi_probe, 324 + .remove = b53_spi_remove, 325 + }; 326 + 327 + module_spi_driver(b53_spi_driver); 328 + 329 + MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>"); 330 + MODULE_DESCRIPTION("B53 SPI access driver"); 331 + MODULE_LICENSE("Dual BSD/GPL");
+415
drivers/net/dsa/b53/b53_srab.c
··· 1 + /* 2 + * B53 register access through Switch Register Access Bridge Registers 3 + * 4 + * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de> 5 + * 6 + * Permission to use, copy, modify, and/or distribute this software for any 7 + * purpose with or without fee is hereby granted, provided that the above 8 + * copyright notice and this permission notice appear in all copies. 9 + * 10 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 + */ 18 + 19 + #include <linux/kernel.h> 20 + #include <linux/module.h> 21 + #include <linux/delay.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/platform_data/b53.h> 24 + 25 + #include "b53_priv.h" 26 + 27 + /* command and status register of the SRAB */ 28 + #define B53_SRAB_CMDSTAT 0x2c 29 + #define B53_SRAB_CMDSTAT_RST BIT(2) 30 + #define B53_SRAB_CMDSTAT_WRITE BIT(1) 31 + #define B53_SRAB_CMDSTAT_GORDYN BIT(0) 32 + #define B53_SRAB_CMDSTAT_PAGE 24 33 + #define B53_SRAB_CMDSTAT_REG 16 34 + 35 + /* high order word of write data to switch registe */ 36 + #define B53_SRAB_WD_H 0x30 37 + 38 + /* low order word of write data to switch registe */ 39 + #define B53_SRAB_WD_L 0x34 40 + 41 + /* high order word of read data from switch register */ 42 + #define B53_SRAB_RD_H 0x38 43 + 44 + /* low order word of read data from switch register */ 45 + #define B53_SRAB_RD_L 0x3c 46 + 47 + /* command and status register of the SRAB */ 48 + #define B53_SRAB_CTRLS 0x40 49 + #define B53_SRAB_CTRLS_RCAREQ BIT(3) 50 + #define B53_SRAB_CTRLS_RCAGNT BIT(4) 51 + #define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6) 52 + 53 + /* the register captures interrupt pulses from the switch */ 54 + #define B53_SRAB_INTR 0x44 55 + #define B53_SRAB_INTR_P(x) BIT(x) 56 + #define B53_SRAB_SWITCH_PHY BIT(8) 57 + #define B53_SRAB_1588_SYNC BIT(9) 58 + #define B53_SRAB_IMP1_SLEEP_TIMER BIT(10) 59 + #define B53_SRAB_P7_SLEEP_TIMER BIT(11) 60 + #define B53_SRAB_IMP0_SLEEP_TIMER BIT(12) 61 + 62 + struct b53_srab_priv { 63 + void __iomem *regs; 64 + }; 65 + 66 + static int b53_srab_request_grant(struct b53_device *dev) 67 + { 68 + struct b53_srab_priv *priv = dev->priv; 69 + u8 __iomem *regs = priv->regs; 70 + u32 ctrls; 71 + int i; 72 + 73 + ctrls = readl(regs + B53_SRAB_CTRLS); 74 + ctrls |= B53_SRAB_CTRLS_RCAREQ; 75 + writel(ctrls, regs + B53_SRAB_CTRLS); 76 + 77 + for (i = 0; i < 20; i++) { 78 + ctrls = readl(regs + B53_SRAB_CTRLS); 79 + if (ctrls & B53_SRAB_CTRLS_RCAGNT) 80 + break; 81 + usleep_range(10, 100); 82 + } 83 + if (WARN_ON(i == 5)) 84 + return -EIO; 85 + 86 + return 0; 87 + } 88 + 89 + static void b53_srab_release_grant(struct b53_device *dev) 90 + { 91 + struct b53_srab_priv *priv = dev->priv; 92 + u8 __iomem *regs = priv->regs; 93 + u32 ctrls; 94 + 95 + ctrls = readl(regs + B53_SRAB_CTRLS); 96 + ctrls &= ~B53_SRAB_CTRLS_RCAREQ; 97 + writel(ctrls, regs + B53_SRAB_CTRLS); 98 + } 99 + 100 + static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op) 101 + { 102 + struct b53_srab_priv *priv = dev->priv; 103 + u8 __iomem *regs = priv->regs; 104 + int i; 105 + u32 cmdstat; 106 + 107 + /* set register address */ 108 + cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) | 109 + (reg << B53_SRAB_CMDSTAT_REG) | 110 + B53_SRAB_CMDSTAT_GORDYN | 111 + op; 112 + writel(cmdstat, regs + B53_SRAB_CMDSTAT); 113 + 114 + /* check if operation completed */ 115 + for (i = 0; i < 5; ++i) { 116 + cmdstat = readl(regs + B53_SRAB_CMDSTAT); 117 + if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN)) 118 + break; 119 + usleep_range(10, 100); 120 + } 121 + 122 + if (WARN_ON(i == 5)) 123 + return -EIO; 124 + 125 + return 0; 126 + } 127 + 128 + static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val) 129 + { 130 + struct b53_srab_priv *priv = dev->priv; 131 + u8 __iomem *regs = priv->regs; 132 + int ret = 0; 133 + 134 + ret = b53_srab_request_grant(dev); 135 + if (ret) 136 + goto err; 137 + 138 + ret = b53_srab_op(dev, page, reg, 0); 139 + if (ret) 140 + goto err; 141 + 142 + *val = readl(regs + B53_SRAB_RD_L) & 0xff; 143 + 144 + err: 145 + b53_srab_release_grant(dev); 146 + 147 + return ret; 148 + } 149 + 150 + static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val) 151 + { 152 + struct b53_srab_priv *priv = dev->priv; 153 + u8 __iomem *regs = priv->regs; 154 + int ret = 0; 155 + 156 + ret = b53_srab_request_grant(dev); 157 + if (ret) 158 + goto err; 159 + 160 + ret = b53_srab_op(dev, page, reg, 0); 161 + if (ret) 162 + goto err; 163 + 164 + *val = readl(regs + B53_SRAB_RD_L) & 0xffff; 165 + 166 + err: 167 + b53_srab_release_grant(dev); 168 + 169 + return ret; 170 + } 171 + 172 + static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val) 173 + { 174 + struct b53_srab_priv *priv = dev->priv; 175 + u8 __iomem *regs = priv->regs; 176 + int ret = 0; 177 + 178 + ret = b53_srab_request_grant(dev); 179 + if (ret) 180 + goto err; 181 + 182 + ret = b53_srab_op(dev, page, reg, 0); 183 + if (ret) 184 + goto err; 185 + 186 + *val = readl(regs + B53_SRAB_RD_L); 187 + 188 + err: 189 + b53_srab_release_grant(dev); 190 + 191 + return ret; 192 + } 193 + 194 + static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val) 195 + { 196 + struct b53_srab_priv *priv = dev->priv; 197 + u8 __iomem *regs = priv->regs; 198 + int ret = 0; 199 + 200 + ret = b53_srab_request_grant(dev); 201 + if (ret) 202 + goto err; 203 + 204 + ret = b53_srab_op(dev, page, reg, 0); 205 + if (ret) 206 + goto err; 207 + 208 + *val = readl(regs + B53_SRAB_RD_L); 209 + *val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32; 210 + 211 + err: 212 + b53_srab_release_grant(dev); 213 + 214 + return ret; 215 + } 216 + 217 + static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val) 218 + { 219 + struct b53_srab_priv *priv = dev->priv; 220 + u8 __iomem *regs = priv->regs; 221 + int ret = 0; 222 + 223 + ret = b53_srab_request_grant(dev); 224 + if (ret) 225 + goto err; 226 + 227 + ret = b53_srab_op(dev, page, reg, 0); 228 + if (ret) 229 + goto err; 230 + 231 + *val = readl(regs + B53_SRAB_RD_L); 232 + *val += (u64)readl(regs + B53_SRAB_RD_H) << 32; 233 + 234 + err: 235 + b53_srab_release_grant(dev); 236 + 237 + return ret; 238 + } 239 + 240 + static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value) 241 + { 242 + struct b53_srab_priv *priv = dev->priv; 243 + u8 __iomem *regs = priv->regs; 244 + int ret = 0; 245 + 246 + ret = b53_srab_request_grant(dev); 247 + if (ret) 248 + goto err; 249 + 250 + writel(value, regs + B53_SRAB_WD_L); 251 + 252 + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); 253 + 254 + err: 255 + b53_srab_release_grant(dev); 256 + 257 + return ret; 258 + } 259 + 260 + static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg, 261 + u16 value) 262 + { 263 + struct b53_srab_priv *priv = dev->priv; 264 + u8 __iomem *regs = priv->regs; 265 + int ret = 0; 266 + 267 + ret = b53_srab_request_grant(dev); 268 + if (ret) 269 + goto err; 270 + 271 + writel(value, regs + B53_SRAB_WD_L); 272 + 273 + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); 274 + 275 + err: 276 + b53_srab_release_grant(dev); 277 + 278 + return ret; 279 + } 280 + 281 + static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg, 282 + u32 value) 283 + { 284 + struct b53_srab_priv *priv = dev->priv; 285 + u8 __iomem *regs = priv->regs; 286 + int ret = 0; 287 + 288 + ret = b53_srab_request_grant(dev); 289 + if (ret) 290 + goto err; 291 + 292 + writel(value, regs + B53_SRAB_WD_L); 293 + 294 + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); 295 + 296 + err: 297 + b53_srab_release_grant(dev); 298 + 299 + return ret; 300 + } 301 + 302 + static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg, 303 + u64 value) 304 + { 305 + struct b53_srab_priv *priv = dev->priv; 306 + u8 __iomem *regs = priv->regs; 307 + int ret = 0; 308 + 309 + ret = b53_srab_request_grant(dev); 310 + if (ret) 311 + goto err; 312 + 313 + writel((u32)value, regs + B53_SRAB_WD_L); 314 + writel((u16)(value >> 32), regs + B53_SRAB_WD_H); 315 + 316 + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); 317 + 318 + err: 319 + b53_srab_release_grant(dev); 320 + 321 + return ret; 322 + } 323 + 324 + static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg, 325 + u64 value) 326 + { 327 + struct b53_srab_priv *priv = dev->priv; 328 + u8 __iomem *regs = priv->regs; 329 + int ret = 0; 330 + 331 + ret = b53_srab_request_grant(dev); 332 + if (ret) 333 + goto err; 334 + 335 + writel((u32)value, regs + B53_SRAB_WD_L); 336 + writel((u32)(value >> 32), regs + B53_SRAB_WD_H); 337 + 338 + ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE); 339 + 340 + err: 341 + b53_srab_release_grant(dev); 342 + 343 + return ret; 344 + } 345 + 346 + static struct b53_io_ops b53_srab_ops = { 347 + .read8 = b53_srab_read8, 348 + .read16 = b53_srab_read16, 349 + .read32 = b53_srab_read32, 350 + .read48 = b53_srab_read48, 351 + .read64 = b53_srab_read64, 352 + .write8 = b53_srab_write8, 353 + .write16 = b53_srab_write16, 354 + .write32 = b53_srab_write32, 355 + .write48 = b53_srab_write48, 356 + .write64 = b53_srab_write64, 357 + }; 358 + 359 + static int b53_srab_probe(struct platform_device *pdev) 360 + { 361 + struct b53_srab_priv *priv; 362 + struct b53_device *dev; 363 + struct resource *r; 364 + 365 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 366 + if (!priv) 367 + return -ENOMEM; 368 + 369 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 370 + priv->regs = devm_ioremap_resource(&pdev->dev, r); 371 + if (IS_ERR(priv->regs)) 372 + return -ENOMEM; 373 + 374 + dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, priv); 375 + if (!dev) 376 + return -ENOMEM; 377 + 378 + platform_set_drvdata(pdev, dev); 379 + 380 + return b53_switch_register(dev); 381 + } 382 + 383 + static int b53_srab_remove(struct platform_device *pdev) 384 + { 385 + struct b53_device *dev = platform_get_drvdata(pdev); 386 + 387 + if (dev) 388 + b53_switch_remove(dev); 389 + 390 + return 0; 391 + } 392 + 393 + static const struct of_device_id b53_srab_of_match[] = { 394 + { .compatible = "brcm,bcm53010-srab" }, 395 + { .compatible = "brcm,bcm53011-srab" }, 396 + { .compatible = "brcm,bcm53012-srab" }, 397 + { .compatible = "brcm,bcm53018-srab" }, 398 + { .compatible = "brcm,bcm53019-srab" }, 399 + { .compatible = "brcm,bcm5301x-srab" }, 400 + { /* sentinel */ }, 401 + }; 402 + 403 + static struct platform_driver b53_srab_driver = { 404 + .probe = b53_srab_probe, 405 + .remove = b53_srab_remove, 406 + .driver = { 407 + .name = "b53-srab-switch", 408 + .of_match_table = b53_srab_of_match, 409 + }, 410 + }; 411 + 412 + module_platform_driver(b53_srab_driver); 413 + MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>"); 414 + MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver"); 415 + MODULE_LICENSE("Dual BSD/GPL");
+33
include/linux/platform_data/b53.h
··· 1 + /* 2 + * B53 platform data 3 + * 4 + * Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org> 5 + * 6 + * Permission to use, copy, modify, and/or distribute this software for any 7 + * purpose with or without fee is hereby granted, provided that the above 8 + * copyright notice and this permission notice appear in all copies. 9 + * 10 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 + */ 18 + 19 + #ifndef __B53_H 20 + #define __B53_H 21 + 22 + #include <linux/kernel.h> 23 + 24 + struct b53_platform_data { 25 + u32 chip_id; 26 + u16 enabled_ports; 27 + 28 + /* only used by MMAP'd driver */ 29 + unsigned big_endian:1; 30 + void __iomem *regs; 31 + }; 32 + 33 + #endif