1*967dd82fSFlorian Fainelli /* 2*967dd82fSFlorian Fainelli * B53 switch driver main logic 3*967dd82fSFlorian Fainelli * 4*967dd82fSFlorian Fainelli * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org> 5*967dd82fSFlorian Fainelli * Copyright (C) 2016 Florian Fainelli <f.fainelli@gmail.com> 6*967dd82fSFlorian Fainelli * 7*967dd82fSFlorian Fainelli * Permission to use, copy, modify, and/or distribute this software for any 8*967dd82fSFlorian Fainelli * purpose with or without fee is hereby granted, provided that the above 9*967dd82fSFlorian Fainelli * copyright notice and this permission notice appear in all copies. 10*967dd82fSFlorian Fainelli * 11*967dd82fSFlorian Fainelli * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12*967dd82fSFlorian Fainelli * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13*967dd82fSFlorian Fainelli * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14*967dd82fSFlorian Fainelli * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15*967dd82fSFlorian Fainelli * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16*967dd82fSFlorian Fainelli * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17*967dd82fSFlorian Fainelli * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18*967dd82fSFlorian Fainelli */ 19*967dd82fSFlorian Fainelli 20*967dd82fSFlorian Fainelli #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 21*967dd82fSFlorian Fainelli 22*967dd82fSFlorian Fainelli #include <linux/delay.h> 23*967dd82fSFlorian Fainelli #include <linux/export.h> 24*967dd82fSFlorian Fainelli #include <linux/gpio.h> 25*967dd82fSFlorian Fainelli #include <linux/kernel.h> 26*967dd82fSFlorian Fainelli #include <linux/module.h> 27*967dd82fSFlorian Fainelli #include <linux/platform_data/b53.h> 28*967dd82fSFlorian Fainelli #include <linux/phy.h> 29*967dd82fSFlorian Fainelli #include <net/dsa.h> 30*967dd82fSFlorian Fainelli 31*967dd82fSFlorian Fainelli #include "b53_regs.h" 32*967dd82fSFlorian Fainelli #include "b53_priv.h" 33*967dd82fSFlorian Fainelli 34*967dd82fSFlorian Fainelli struct b53_mib_desc { 35*967dd82fSFlorian Fainelli u8 size; 36*967dd82fSFlorian Fainelli u8 offset; 37*967dd82fSFlorian Fainelli const char *name; 38*967dd82fSFlorian Fainelli }; 39*967dd82fSFlorian Fainelli 40*967dd82fSFlorian Fainelli /* BCM5365 MIB counters */ 41*967dd82fSFlorian Fainelli static const struct b53_mib_desc b53_mibs_65[] = { 42*967dd82fSFlorian Fainelli { 8, 0x00, "TxOctets" }, 43*967dd82fSFlorian Fainelli { 4, 0x08, "TxDropPkts" }, 44*967dd82fSFlorian Fainelli { 4, 0x10, "TxBroadcastPkts" }, 45*967dd82fSFlorian Fainelli { 4, 0x14, "TxMulticastPkts" }, 46*967dd82fSFlorian Fainelli { 4, 0x18, "TxUnicastPkts" }, 47*967dd82fSFlorian Fainelli { 4, 0x1c, "TxCollisions" }, 48*967dd82fSFlorian Fainelli { 4, 0x20, "TxSingleCollision" }, 49*967dd82fSFlorian Fainelli { 4, 0x24, "TxMultipleCollision" }, 50*967dd82fSFlorian Fainelli { 4, 0x28, "TxDeferredTransmit" }, 51*967dd82fSFlorian Fainelli { 4, 0x2c, "TxLateCollision" }, 52*967dd82fSFlorian Fainelli { 4, 0x30, "TxExcessiveCollision" }, 53*967dd82fSFlorian Fainelli { 4, 0x38, "TxPausePkts" }, 54*967dd82fSFlorian Fainelli { 8, 0x44, "RxOctets" }, 55*967dd82fSFlorian Fainelli { 4, 0x4c, "RxUndersizePkts" }, 56*967dd82fSFlorian Fainelli { 4, 0x50, "RxPausePkts" }, 57*967dd82fSFlorian Fainelli { 4, 0x54, "Pkts64Octets" }, 58*967dd82fSFlorian Fainelli { 4, 0x58, "Pkts65to127Octets" }, 59*967dd82fSFlorian Fainelli { 4, 0x5c, "Pkts128to255Octets" }, 60*967dd82fSFlorian Fainelli { 4, 0x60, "Pkts256to511Octets" }, 61*967dd82fSFlorian Fainelli { 4, 0x64, "Pkts512to1023Octets" }, 62*967dd82fSFlorian Fainelli { 4, 0x68, "Pkts1024to1522Octets" }, 63*967dd82fSFlorian Fainelli { 4, 0x6c, "RxOversizePkts" }, 64*967dd82fSFlorian Fainelli { 4, 0x70, "RxJabbers" }, 65*967dd82fSFlorian Fainelli { 4, 0x74, "RxAlignmentErrors" }, 66*967dd82fSFlorian Fainelli { 4, 0x78, "RxFCSErrors" }, 67*967dd82fSFlorian Fainelli { 8, 0x7c, "RxGoodOctets" }, 68*967dd82fSFlorian Fainelli { 4, 0x84, "RxDropPkts" }, 69*967dd82fSFlorian Fainelli { 4, 0x88, "RxUnicastPkts" }, 70*967dd82fSFlorian Fainelli { 4, 0x8c, "RxMulticastPkts" }, 71*967dd82fSFlorian Fainelli { 4, 0x90, "RxBroadcastPkts" }, 72*967dd82fSFlorian Fainelli { 4, 0x94, "RxSAChanges" }, 73*967dd82fSFlorian Fainelli { 4, 0x98, "RxFragments" }, 74*967dd82fSFlorian Fainelli }; 75*967dd82fSFlorian Fainelli 76*967dd82fSFlorian Fainelli #define B53_MIBS_65_SIZE ARRAY_SIZE(b53_mibs_65) 77*967dd82fSFlorian Fainelli 78*967dd82fSFlorian Fainelli /* BCM63xx MIB counters */ 79*967dd82fSFlorian Fainelli static const struct b53_mib_desc b53_mibs_63xx[] = { 80*967dd82fSFlorian Fainelli { 8, 0x00, "TxOctets" }, 81*967dd82fSFlorian Fainelli { 4, 0x08, "TxDropPkts" }, 82*967dd82fSFlorian Fainelli { 4, 0x0c, "TxQoSPkts" }, 83*967dd82fSFlorian Fainelli { 4, 0x10, "TxBroadcastPkts" }, 84*967dd82fSFlorian Fainelli { 4, 0x14, "TxMulticastPkts" }, 85*967dd82fSFlorian Fainelli { 4, 0x18, "TxUnicastPkts" }, 86*967dd82fSFlorian Fainelli { 4, 0x1c, "TxCollisions" }, 87*967dd82fSFlorian Fainelli { 4, 0x20, "TxSingleCollision" }, 88*967dd82fSFlorian Fainelli { 4, 0x24, "TxMultipleCollision" }, 89*967dd82fSFlorian Fainelli { 4, 0x28, "TxDeferredTransmit" }, 90*967dd82fSFlorian Fainelli { 4, 0x2c, "TxLateCollision" }, 91*967dd82fSFlorian Fainelli { 4, 0x30, "TxExcessiveCollision" }, 92*967dd82fSFlorian Fainelli { 4, 0x38, "TxPausePkts" }, 93*967dd82fSFlorian Fainelli { 8, 0x3c, "TxQoSOctets" }, 94*967dd82fSFlorian Fainelli { 8, 0x44, "RxOctets" }, 95*967dd82fSFlorian Fainelli { 4, 0x4c, "RxUndersizePkts" }, 96*967dd82fSFlorian Fainelli { 4, 0x50, "RxPausePkts" }, 97*967dd82fSFlorian Fainelli { 4, 0x54, "Pkts64Octets" }, 98*967dd82fSFlorian Fainelli { 4, 0x58, "Pkts65to127Octets" }, 99*967dd82fSFlorian Fainelli { 4, 0x5c, "Pkts128to255Octets" }, 100*967dd82fSFlorian Fainelli { 4, 0x60, "Pkts256to511Octets" }, 101*967dd82fSFlorian Fainelli { 4, 0x64, "Pkts512to1023Octets" }, 102*967dd82fSFlorian Fainelli { 4, 0x68, "Pkts1024to1522Octets" }, 103*967dd82fSFlorian Fainelli { 4, 0x6c, "RxOversizePkts" }, 104*967dd82fSFlorian Fainelli { 4, 0x70, "RxJabbers" }, 105*967dd82fSFlorian Fainelli { 4, 0x74, "RxAlignmentErrors" }, 106*967dd82fSFlorian Fainelli { 4, 0x78, "RxFCSErrors" }, 107*967dd82fSFlorian Fainelli { 8, 0x7c, "RxGoodOctets" }, 108*967dd82fSFlorian Fainelli { 4, 0x84, "RxDropPkts" }, 109*967dd82fSFlorian Fainelli { 4, 0x88, "RxUnicastPkts" }, 110*967dd82fSFlorian Fainelli { 4, 0x8c, "RxMulticastPkts" }, 111*967dd82fSFlorian Fainelli { 4, 0x90, "RxBroadcastPkts" }, 112*967dd82fSFlorian Fainelli { 4, 0x94, "RxSAChanges" }, 113*967dd82fSFlorian Fainelli { 4, 0x98, "RxFragments" }, 114*967dd82fSFlorian Fainelli { 4, 0xa0, "RxSymbolErrors" }, 115*967dd82fSFlorian Fainelli { 4, 0xa4, "RxQoSPkts" }, 116*967dd82fSFlorian Fainelli { 8, 0xa8, "RxQoSOctets" }, 117*967dd82fSFlorian Fainelli { 4, 0xb0, "Pkts1523to2047Octets" }, 118*967dd82fSFlorian Fainelli { 4, 0xb4, "Pkts2048to4095Octets" }, 119*967dd82fSFlorian Fainelli { 4, 0xb8, "Pkts4096to8191Octets" }, 120*967dd82fSFlorian Fainelli { 4, 0xbc, "Pkts8192to9728Octets" }, 121*967dd82fSFlorian Fainelli { 4, 0xc0, "RxDiscarded" }, 122*967dd82fSFlorian Fainelli }; 123*967dd82fSFlorian Fainelli 124*967dd82fSFlorian Fainelli #define B53_MIBS_63XX_SIZE ARRAY_SIZE(b53_mibs_63xx) 125*967dd82fSFlorian Fainelli 126*967dd82fSFlorian Fainelli /* MIB counters */ 127*967dd82fSFlorian Fainelli static const struct b53_mib_desc b53_mibs[] = { 128*967dd82fSFlorian Fainelli { 8, 0x00, "TxOctets" }, 129*967dd82fSFlorian Fainelli { 4, 0x08, "TxDropPkts" }, 130*967dd82fSFlorian Fainelli { 4, 0x10, "TxBroadcastPkts" }, 131*967dd82fSFlorian Fainelli { 4, 0x14, "TxMulticastPkts" }, 132*967dd82fSFlorian Fainelli { 4, 0x18, "TxUnicastPkts" }, 133*967dd82fSFlorian Fainelli { 4, 0x1c, "TxCollisions" }, 134*967dd82fSFlorian Fainelli { 4, 0x20, "TxSingleCollision" }, 135*967dd82fSFlorian Fainelli { 4, 0x24, "TxMultipleCollision" }, 136*967dd82fSFlorian Fainelli { 4, 0x28, "TxDeferredTransmit" }, 137*967dd82fSFlorian Fainelli { 4, 0x2c, "TxLateCollision" }, 138*967dd82fSFlorian Fainelli { 4, 0x30, "TxExcessiveCollision" }, 139*967dd82fSFlorian Fainelli { 4, 0x38, "TxPausePkts" }, 140*967dd82fSFlorian Fainelli { 8, 0x50, "RxOctets" }, 141*967dd82fSFlorian Fainelli { 4, 0x58, "RxUndersizePkts" }, 142*967dd82fSFlorian Fainelli { 4, 0x5c, "RxPausePkts" }, 143*967dd82fSFlorian Fainelli { 4, 0x60, "Pkts64Octets" }, 144*967dd82fSFlorian Fainelli { 4, 0x64, "Pkts65to127Octets" }, 145*967dd82fSFlorian Fainelli { 4, 0x68, "Pkts128to255Octets" }, 146*967dd82fSFlorian Fainelli { 4, 0x6c, "Pkts256to511Octets" }, 147*967dd82fSFlorian Fainelli { 4, 0x70, "Pkts512to1023Octets" }, 148*967dd82fSFlorian Fainelli { 4, 0x74, "Pkts1024to1522Octets" }, 149*967dd82fSFlorian Fainelli { 4, 0x78, "RxOversizePkts" }, 150*967dd82fSFlorian Fainelli { 4, 0x7c, "RxJabbers" }, 151*967dd82fSFlorian Fainelli { 4, 0x80, "RxAlignmentErrors" }, 152*967dd82fSFlorian Fainelli { 4, 0x84, "RxFCSErrors" }, 153*967dd82fSFlorian Fainelli { 8, 0x88, "RxGoodOctets" }, 154*967dd82fSFlorian Fainelli { 4, 0x90, "RxDropPkts" }, 155*967dd82fSFlorian Fainelli { 4, 0x94, "RxUnicastPkts" }, 156*967dd82fSFlorian Fainelli { 4, 0x98, "RxMulticastPkts" }, 157*967dd82fSFlorian Fainelli { 4, 0x9c, "RxBroadcastPkts" }, 158*967dd82fSFlorian Fainelli { 4, 0xa0, "RxSAChanges" }, 159*967dd82fSFlorian Fainelli { 4, 0xa4, "RxFragments" }, 160*967dd82fSFlorian Fainelli { 4, 0xa8, "RxJumboPkts" }, 161*967dd82fSFlorian Fainelli { 4, 0xac, "RxSymbolErrors" }, 162*967dd82fSFlorian Fainelli { 4, 0xc0, "RxDiscarded" }, 163*967dd82fSFlorian Fainelli }; 164*967dd82fSFlorian Fainelli 165*967dd82fSFlorian Fainelli #define B53_MIBS_SIZE ARRAY_SIZE(b53_mibs) 166*967dd82fSFlorian Fainelli 167*967dd82fSFlorian Fainelli static int b53_do_vlan_op(struct b53_device *dev, u8 op) 168*967dd82fSFlorian Fainelli { 169*967dd82fSFlorian Fainelli unsigned int i; 170*967dd82fSFlorian Fainelli 171*967dd82fSFlorian Fainelli b53_write8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], VTA_START_CMD | op); 172*967dd82fSFlorian Fainelli 173*967dd82fSFlorian Fainelli for (i = 0; i < 10; i++) { 174*967dd82fSFlorian Fainelli u8 vta; 175*967dd82fSFlorian Fainelli 176*967dd82fSFlorian Fainelli b53_read8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], &vta); 177*967dd82fSFlorian Fainelli if (!(vta & VTA_START_CMD)) 178*967dd82fSFlorian Fainelli return 0; 179*967dd82fSFlorian Fainelli 180*967dd82fSFlorian Fainelli usleep_range(100, 200); 181*967dd82fSFlorian Fainelli } 182*967dd82fSFlorian Fainelli 183*967dd82fSFlorian Fainelli return -EIO; 184*967dd82fSFlorian Fainelli } 185*967dd82fSFlorian Fainelli 186*967dd82fSFlorian Fainelli static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members, 187*967dd82fSFlorian Fainelli u16 untag) 188*967dd82fSFlorian Fainelli { 189*967dd82fSFlorian Fainelli if (is5325(dev)) { 190*967dd82fSFlorian Fainelli u32 entry = 0; 191*967dd82fSFlorian Fainelli 192*967dd82fSFlorian Fainelli if (members) { 193*967dd82fSFlorian Fainelli entry = ((untag & VA_UNTAG_MASK_25) << VA_UNTAG_S_25) | 194*967dd82fSFlorian Fainelli members; 195*967dd82fSFlorian Fainelli if (dev->core_rev >= 3) 196*967dd82fSFlorian Fainelli entry |= VA_VALID_25_R4 | vid << VA_VID_HIGH_S; 197*967dd82fSFlorian Fainelli else 198*967dd82fSFlorian Fainelli entry |= VA_VALID_25; 199*967dd82fSFlorian Fainelli } 200*967dd82fSFlorian Fainelli 201*967dd82fSFlorian Fainelli b53_write32(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_25, entry); 202*967dd82fSFlorian Fainelli b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, vid | 203*967dd82fSFlorian Fainelli VTA_RW_STATE_WR | VTA_RW_OP_EN); 204*967dd82fSFlorian Fainelli } else if (is5365(dev)) { 205*967dd82fSFlorian Fainelli u16 entry = 0; 206*967dd82fSFlorian Fainelli 207*967dd82fSFlorian Fainelli if (members) 208*967dd82fSFlorian Fainelli entry = ((untag & VA_UNTAG_MASK_65) << VA_UNTAG_S_65) | 209*967dd82fSFlorian Fainelli members | VA_VALID_65; 210*967dd82fSFlorian Fainelli 211*967dd82fSFlorian Fainelli b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_65, entry); 212*967dd82fSFlorian Fainelli b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_65, vid | 213*967dd82fSFlorian Fainelli VTA_RW_STATE_WR | VTA_RW_OP_EN); 214*967dd82fSFlorian Fainelli } else { 215*967dd82fSFlorian Fainelli b53_write16(dev, B53_ARLIO_PAGE, dev->vta_regs[1], vid); 216*967dd82fSFlorian Fainelli b53_write32(dev, B53_ARLIO_PAGE, dev->vta_regs[2], 217*967dd82fSFlorian Fainelli (untag << VTE_UNTAG_S) | members); 218*967dd82fSFlorian Fainelli 219*967dd82fSFlorian Fainelli b53_do_vlan_op(dev, VTA_CMD_WRITE); 220*967dd82fSFlorian Fainelli } 221*967dd82fSFlorian Fainelli } 222*967dd82fSFlorian Fainelli 223*967dd82fSFlorian Fainelli void b53_set_forwarding(struct b53_device *dev, int enable) 224*967dd82fSFlorian Fainelli { 225*967dd82fSFlorian Fainelli u8 mgmt; 226*967dd82fSFlorian Fainelli 227*967dd82fSFlorian Fainelli b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); 228*967dd82fSFlorian Fainelli 229*967dd82fSFlorian Fainelli if (enable) 230*967dd82fSFlorian Fainelli mgmt |= SM_SW_FWD_EN; 231*967dd82fSFlorian Fainelli else 232*967dd82fSFlorian Fainelli mgmt &= ~SM_SW_FWD_EN; 233*967dd82fSFlorian Fainelli 234*967dd82fSFlorian Fainelli b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); 235*967dd82fSFlorian Fainelli } 236*967dd82fSFlorian Fainelli 237*967dd82fSFlorian Fainelli static void b53_enable_vlan(struct b53_device *dev, int enable) 238*967dd82fSFlorian Fainelli { 239*967dd82fSFlorian Fainelli u8 mgmt, vc0, vc1, vc4 = 0, vc5; 240*967dd82fSFlorian Fainelli 241*967dd82fSFlorian Fainelli b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); 242*967dd82fSFlorian Fainelli b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, &vc0); 243*967dd82fSFlorian Fainelli b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, &vc1); 244*967dd82fSFlorian Fainelli 245*967dd82fSFlorian Fainelli if (is5325(dev) || is5365(dev)) { 246*967dd82fSFlorian Fainelli b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4); 247*967dd82fSFlorian Fainelli b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, &vc5); 248*967dd82fSFlorian Fainelli } else if (is63xx(dev)) { 249*967dd82fSFlorian Fainelli b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, &vc4); 250*967dd82fSFlorian Fainelli b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, &vc5); 251*967dd82fSFlorian Fainelli } else { 252*967dd82fSFlorian Fainelli b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, &vc4); 253*967dd82fSFlorian Fainelli b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5); 254*967dd82fSFlorian Fainelli } 255*967dd82fSFlorian Fainelli 256*967dd82fSFlorian Fainelli mgmt &= ~SM_SW_FWD_MODE; 257*967dd82fSFlorian Fainelli 258*967dd82fSFlorian Fainelli if (enable) { 259*967dd82fSFlorian Fainelli vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID; 260*967dd82fSFlorian Fainelli vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN; 261*967dd82fSFlorian Fainelli vc4 &= ~VC4_ING_VID_CHECK_MASK; 262*967dd82fSFlorian Fainelli vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S; 263*967dd82fSFlorian Fainelli vc5 |= VC5_DROP_VTABLE_MISS; 264*967dd82fSFlorian Fainelli 265*967dd82fSFlorian Fainelli if (is5325(dev)) 266*967dd82fSFlorian Fainelli vc0 &= ~VC0_RESERVED_1; 267*967dd82fSFlorian Fainelli 268*967dd82fSFlorian Fainelli if (is5325(dev) || is5365(dev)) 269*967dd82fSFlorian Fainelli vc1 |= VC1_RX_MCST_TAG_EN; 270*967dd82fSFlorian Fainelli 271*967dd82fSFlorian Fainelli if (!is5325(dev) && !is5365(dev)) { 272*967dd82fSFlorian Fainelli if (dev->allow_vid_4095) 273*967dd82fSFlorian Fainelli vc5 |= VC5_VID_FFF_EN; 274*967dd82fSFlorian Fainelli else 275*967dd82fSFlorian Fainelli vc5 &= ~VC5_VID_FFF_EN; 276*967dd82fSFlorian Fainelli } 277*967dd82fSFlorian Fainelli } else { 278*967dd82fSFlorian Fainelli vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID); 279*967dd82fSFlorian Fainelli vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN); 280*967dd82fSFlorian Fainelli vc4 &= ~VC4_ING_VID_CHECK_MASK; 281*967dd82fSFlorian Fainelli vc5 &= ~VC5_DROP_VTABLE_MISS; 282*967dd82fSFlorian Fainelli 283*967dd82fSFlorian Fainelli if (is5325(dev) || is5365(dev)) 284*967dd82fSFlorian Fainelli vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S; 285*967dd82fSFlorian Fainelli else 286*967dd82fSFlorian Fainelli vc4 |= VC4_ING_VID_VIO_TO_IMP << VC4_ING_VID_CHECK_S; 287*967dd82fSFlorian Fainelli 288*967dd82fSFlorian Fainelli if (is5325(dev) || is5365(dev)) 289*967dd82fSFlorian Fainelli vc1 &= ~VC1_RX_MCST_TAG_EN; 290*967dd82fSFlorian Fainelli 291*967dd82fSFlorian Fainelli if (!is5325(dev) && !is5365(dev)) 292*967dd82fSFlorian Fainelli vc5 &= ~VC5_VID_FFF_EN; 293*967dd82fSFlorian Fainelli } 294*967dd82fSFlorian Fainelli 295*967dd82fSFlorian Fainelli b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, vc0); 296*967dd82fSFlorian Fainelli b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, vc1); 297*967dd82fSFlorian Fainelli 298*967dd82fSFlorian Fainelli if (is5325(dev) || is5365(dev)) { 299*967dd82fSFlorian Fainelli /* enable the high 8 bit vid check on 5325 */ 300*967dd82fSFlorian Fainelli if (is5325(dev) && enable) 301*967dd82fSFlorian Fainelli b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 302*967dd82fSFlorian Fainelli VC3_HIGH_8BIT_EN); 303*967dd82fSFlorian Fainelli else 304*967dd82fSFlorian Fainelli b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0); 305*967dd82fSFlorian Fainelli 306*967dd82fSFlorian Fainelli b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, vc4); 307*967dd82fSFlorian Fainelli b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, vc5); 308*967dd82fSFlorian Fainelli } else if (is63xx(dev)) { 309*967dd82fSFlorian Fainelli b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3_63XX, 0); 310*967dd82fSFlorian Fainelli b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, vc4); 311*967dd82fSFlorian Fainelli b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, vc5); 312*967dd82fSFlorian Fainelli } else { 313*967dd82fSFlorian Fainelli b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0); 314*967dd82fSFlorian Fainelli b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, vc4); 315*967dd82fSFlorian Fainelli b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, vc5); 316*967dd82fSFlorian Fainelli } 317*967dd82fSFlorian Fainelli 318*967dd82fSFlorian Fainelli b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); 319*967dd82fSFlorian Fainelli } 320*967dd82fSFlorian Fainelli 321*967dd82fSFlorian Fainelli static int b53_set_jumbo(struct b53_device *dev, bool enable, bool allow_10_100) 322*967dd82fSFlorian Fainelli { 323*967dd82fSFlorian Fainelli u32 port_mask = 0; 324*967dd82fSFlorian Fainelli u16 max_size = JMS_MIN_SIZE; 325*967dd82fSFlorian Fainelli 326*967dd82fSFlorian Fainelli if (is5325(dev) || is5365(dev)) 327*967dd82fSFlorian Fainelli return -EINVAL; 328*967dd82fSFlorian Fainelli 329*967dd82fSFlorian Fainelli if (enable) { 330*967dd82fSFlorian Fainelli port_mask = dev->enabled_ports; 331*967dd82fSFlorian Fainelli max_size = JMS_MAX_SIZE; 332*967dd82fSFlorian Fainelli if (allow_10_100) 333*967dd82fSFlorian Fainelli port_mask |= JPM_10_100_JUMBO_EN; 334*967dd82fSFlorian Fainelli } 335*967dd82fSFlorian Fainelli 336*967dd82fSFlorian Fainelli b53_write32(dev, B53_JUMBO_PAGE, dev->jumbo_pm_reg, port_mask); 337*967dd82fSFlorian Fainelli return b53_write16(dev, B53_JUMBO_PAGE, dev->jumbo_size_reg, max_size); 338*967dd82fSFlorian Fainelli } 339*967dd82fSFlorian Fainelli 340*967dd82fSFlorian Fainelli static int b53_flush_arl(struct b53_device *dev) 341*967dd82fSFlorian Fainelli { 342*967dd82fSFlorian Fainelli unsigned int i; 343*967dd82fSFlorian Fainelli 344*967dd82fSFlorian Fainelli b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, 345*967dd82fSFlorian Fainelli FAST_AGE_DONE | FAST_AGE_DYNAMIC | FAST_AGE_STATIC); 346*967dd82fSFlorian Fainelli 347*967dd82fSFlorian Fainelli for (i = 0; i < 10; i++) { 348*967dd82fSFlorian Fainelli u8 fast_age_ctrl; 349*967dd82fSFlorian Fainelli 350*967dd82fSFlorian Fainelli b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, 351*967dd82fSFlorian Fainelli &fast_age_ctrl); 352*967dd82fSFlorian Fainelli 353*967dd82fSFlorian Fainelli if (!(fast_age_ctrl & FAST_AGE_DONE)) 354*967dd82fSFlorian Fainelli goto out; 355*967dd82fSFlorian Fainelli 356*967dd82fSFlorian Fainelli msleep(1); 357*967dd82fSFlorian Fainelli } 358*967dd82fSFlorian Fainelli 359*967dd82fSFlorian Fainelli return -ETIMEDOUT; 360*967dd82fSFlorian Fainelli out: 361*967dd82fSFlorian Fainelli /* Only age dynamic entries (default behavior) */ 362*967dd82fSFlorian Fainelli b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, FAST_AGE_DYNAMIC); 363*967dd82fSFlorian Fainelli return 0; 364*967dd82fSFlorian Fainelli } 365*967dd82fSFlorian Fainelli 366*967dd82fSFlorian Fainelli static int b53_enable_port(struct dsa_switch *ds, int port, 367*967dd82fSFlorian Fainelli struct phy_device *phy) 368*967dd82fSFlorian Fainelli { 369*967dd82fSFlorian Fainelli struct b53_device *dev = ds_to_priv(ds); 370*967dd82fSFlorian Fainelli 371*967dd82fSFlorian Fainelli /* Clear the Rx and Tx disable bits and set to no spanning tree */ 372*967dd82fSFlorian Fainelli b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), 0); 373*967dd82fSFlorian Fainelli 374*967dd82fSFlorian Fainelli return 0; 375*967dd82fSFlorian Fainelli } 376*967dd82fSFlorian Fainelli 377*967dd82fSFlorian Fainelli static void b53_disable_port(struct dsa_switch *ds, int port, 378*967dd82fSFlorian Fainelli struct phy_device *phy) 379*967dd82fSFlorian Fainelli { 380*967dd82fSFlorian Fainelli struct b53_device *dev = ds_to_priv(ds); 381*967dd82fSFlorian Fainelli u8 reg; 382*967dd82fSFlorian Fainelli 383*967dd82fSFlorian Fainelli /* Disable Tx/Rx for the port */ 384*967dd82fSFlorian Fainelli b53_read8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), ®); 385*967dd82fSFlorian Fainelli reg |= PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE; 386*967dd82fSFlorian Fainelli b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), reg); 387*967dd82fSFlorian Fainelli } 388*967dd82fSFlorian Fainelli 389*967dd82fSFlorian Fainelli static void b53_enable_cpu_port(struct b53_device *dev) 390*967dd82fSFlorian Fainelli { 391*967dd82fSFlorian Fainelli unsigned int cpu_port = dev->cpu_port; 392*967dd82fSFlorian Fainelli u8 port_ctrl; 393*967dd82fSFlorian Fainelli 394*967dd82fSFlorian Fainelli /* BCM5325 CPU port is at 8 */ 395*967dd82fSFlorian Fainelli if ((is5325(dev) || is5365(dev)) && cpu_port == B53_CPU_PORT_25) 396*967dd82fSFlorian Fainelli cpu_port = B53_CPU_PORT; 397*967dd82fSFlorian Fainelli 398*967dd82fSFlorian Fainelli port_ctrl = PORT_CTRL_RX_BCST_EN | 399*967dd82fSFlorian Fainelli PORT_CTRL_RX_MCST_EN | 400*967dd82fSFlorian Fainelli PORT_CTRL_RX_UCST_EN; 401*967dd82fSFlorian Fainelli b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(cpu_port), port_ctrl); 402*967dd82fSFlorian Fainelli } 403*967dd82fSFlorian Fainelli 404*967dd82fSFlorian Fainelli static void b53_enable_mib(struct b53_device *dev) 405*967dd82fSFlorian Fainelli { 406*967dd82fSFlorian Fainelli u8 gc; 407*967dd82fSFlorian Fainelli 408*967dd82fSFlorian Fainelli b53_read8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); 409*967dd82fSFlorian Fainelli gc &= ~(GC_RESET_MIB | GC_MIB_AC_EN); 410*967dd82fSFlorian Fainelli b53_write8(dev, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc); 411*967dd82fSFlorian Fainelli } 412*967dd82fSFlorian Fainelli 413*967dd82fSFlorian Fainelli static int b53_configure_vlan(struct b53_device *dev) 414*967dd82fSFlorian Fainelli { 415*967dd82fSFlorian Fainelli int i; 416*967dd82fSFlorian Fainelli 417*967dd82fSFlorian Fainelli /* clear all vlan entries */ 418*967dd82fSFlorian Fainelli if (is5325(dev) || is5365(dev)) { 419*967dd82fSFlorian Fainelli for (i = 1; i < dev->num_vlans; i++) 420*967dd82fSFlorian Fainelli b53_set_vlan_entry(dev, i, 0, 0); 421*967dd82fSFlorian Fainelli } else { 422*967dd82fSFlorian Fainelli b53_do_vlan_op(dev, VTA_CMD_CLEAR); 423*967dd82fSFlorian Fainelli } 424*967dd82fSFlorian Fainelli 425*967dd82fSFlorian Fainelli b53_enable_vlan(dev, false); 426*967dd82fSFlorian Fainelli 427*967dd82fSFlorian Fainelli b53_for_each_port(dev, i) 428*967dd82fSFlorian Fainelli b53_write16(dev, B53_VLAN_PAGE, 429*967dd82fSFlorian Fainelli B53_VLAN_PORT_DEF_TAG(i), 1); 430*967dd82fSFlorian Fainelli 431*967dd82fSFlorian Fainelli if (!is5325(dev) && !is5365(dev)) 432*967dd82fSFlorian Fainelli b53_set_jumbo(dev, dev->enable_jumbo, false); 433*967dd82fSFlorian Fainelli 434*967dd82fSFlorian Fainelli return 0; 435*967dd82fSFlorian Fainelli } 436*967dd82fSFlorian Fainelli 437*967dd82fSFlorian Fainelli static void b53_switch_reset_gpio(struct b53_device *dev) 438*967dd82fSFlorian Fainelli { 439*967dd82fSFlorian Fainelli int gpio = dev->reset_gpio; 440*967dd82fSFlorian Fainelli 441*967dd82fSFlorian Fainelli if (gpio < 0) 442*967dd82fSFlorian Fainelli return; 443*967dd82fSFlorian Fainelli 444*967dd82fSFlorian Fainelli /* Reset sequence: RESET low(50ms)->high(20ms) 445*967dd82fSFlorian Fainelli */ 446*967dd82fSFlorian Fainelli gpio_set_value(gpio, 0); 447*967dd82fSFlorian Fainelli mdelay(50); 448*967dd82fSFlorian Fainelli 449*967dd82fSFlorian Fainelli gpio_set_value(gpio, 1); 450*967dd82fSFlorian Fainelli mdelay(20); 451*967dd82fSFlorian Fainelli 452*967dd82fSFlorian Fainelli dev->current_page = 0xff; 453*967dd82fSFlorian Fainelli } 454*967dd82fSFlorian Fainelli 455*967dd82fSFlorian Fainelli static int b53_switch_reset(struct b53_device *dev) 456*967dd82fSFlorian Fainelli { 457*967dd82fSFlorian Fainelli u8 mgmt; 458*967dd82fSFlorian Fainelli 459*967dd82fSFlorian Fainelli b53_switch_reset_gpio(dev); 460*967dd82fSFlorian Fainelli 461*967dd82fSFlorian Fainelli if (is539x(dev)) { 462*967dd82fSFlorian Fainelli b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x83); 463*967dd82fSFlorian Fainelli b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x00); 464*967dd82fSFlorian Fainelli } 465*967dd82fSFlorian Fainelli 466*967dd82fSFlorian Fainelli b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); 467*967dd82fSFlorian Fainelli 468*967dd82fSFlorian Fainelli if (!(mgmt & SM_SW_FWD_EN)) { 469*967dd82fSFlorian Fainelli mgmt &= ~SM_SW_FWD_MODE; 470*967dd82fSFlorian Fainelli mgmt |= SM_SW_FWD_EN; 471*967dd82fSFlorian Fainelli 472*967dd82fSFlorian Fainelli b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); 473*967dd82fSFlorian Fainelli b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); 474*967dd82fSFlorian Fainelli 475*967dd82fSFlorian Fainelli if (!(mgmt & SM_SW_FWD_EN)) { 476*967dd82fSFlorian Fainelli dev_err(dev->dev, "Failed to enable switch!\n"); 477*967dd82fSFlorian Fainelli return -EINVAL; 478*967dd82fSFlorian Fainelli } 479*967dd82fSFlorian Fainelli } 480*967dd82fSFlorian Fainelli 481*967dd82fSFlorian Fainelli b53_enable_mib(dev); 482*967dd82fSFlorian Fainelli 483*967dd82fSFlorian Fainelli return b53_flush_arl(dev); 484*967dd82fSFlorian Fainelli } 485*967dd82fSFlorian Fainelli 486*967dd82fSFlorian Fainelli static int b53_phy_read16(struct dsa_switch *ds, int addr, int reg) 487*967dd82fSFlorian Fainelli { 488*967dd82fSFlorian Fainelli struct b53_device *priv = ds_to_priv(ds); 489*967dd82fSFlorian Fainelli u16 value = 0; 490*967dd82fSFlorian Fainelli int ret; 491*967dd82fSFlorian Fainelli 492*967dd82fSFlorian Fainelli if (priv->ops->phy_read16) 493*967dd82fSFlorian Fainelli ret = priv->ops->phy_read16(priv, addr, reg, &value); 494*967dd82fSFlorian Fainelli else 495*967dd82fSFlorian Fainelli ret = b53_read16(priv, B53_PORT_MII_PAGE(addr), 496*967dd82fSFlorian Fainelli reg * 2, &value); 497*967dd82fSFlorian Fainelli 498*967dd82fSFlorian Fainelli return ret ? ret : value; 499*967dd82fSFlorian Fainelli } 500*967dd82fSFlorian Fainelli 501*967dd82fSFlorian Fainelli static int b53_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) 502*967dd82fSFlorian Fainelli { 503*967dd82fSFlorian Fainelli struct b53_device *priv = ds_to_priv(ds); 504*967dd82fSFlorian Fainelli 505*967dd82fSFlorian Fainelli if (priv->ops->phy_write16) 506*967dd82fSFlorian Fainelli return priv->ops->phy_write16(priv, addr, reg, val); 507*967dd82fSFlorian Fainelli 508*967dd82fSFlorian Fainelli return b53_write16(priv, B53_PORT_MII_PAGE(addr), reg * 2, val); 509*967dd82fSFlorian Fainelli } 510*967dd82fSFlorian Fainelli 511*967dd82fSFlorian Fainelli static int b53_reset_switch(struct b53_device *priv) 512*967dd82fSFlorian Fainelli { 513*967dd82fSFlorian Fainelli /* reset vlans */ 514*967dd82fSFlorian Fainelli priv->enable_jumbo = false; 515*967dd82fSFlorian Fainelli 516*967dd82fSFlorian Fainelli memset(priv->ports, 0, sizeof(*priv->ports) * priv->num_ports); 517*967dd82fSFlorian Fainelli 518*967dd82fSFlorian Fainelli return b53_switch_reset(priv); 519*967dd82fSFlorian Fainelli } 520*967dd82fSFlorian Fainelli 521*967dd82fSFlorian Fainelli static int b53_apply_config(struct b53_device *priv) 522*967dd82fSFlorian Fainelli { 523*967dd82fSFlorian Fainelli /* disable switching */ 524*967dd82fSFlorian Fainelli b53_set_forwarding(priv, 0); 525*967dd82fSFlorian Fainelli 526*967dd82fSFlorian Fainelli b53_configure_vlan(priv); 527*967dd82fSFlorian Fainelli 528*967dd82fSFlorian Fainelli /* enable switching */ 529*967dd82fSFlorian Fainelli b53_set_forwarding(priv, 1); 530*967dd82fSFlorian Fainelli 531*967dd82fSFlorian Fainelli return 0; 532*967dd82fSFlorian Fainelli } 533*967dd82fSFlorian Fainelli 534*967dd82fSFlorian Fainelli static void b53_reset_mib(struct b53_device *priv) 535*967dd82fSFlorian Fainelli { 536*967dd82fSFlorian Fainelli u8 gc; 537*967dd82fSFlorian Fainelli 538*967dd82fSFlorian Fainelli b53_read8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc); 539*967dd82fSFlorian Fainelli 540*967dd82fSFlorian Fainelli b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc | GC_RESET_MIB); 541*967dd82fSFlorian Fainelli msleep(1); 542*967dd82fSFlorian Fainelli b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc & ~GC_RESET_MIB); 543*967dd82fSFlorian Fainelli msleep(1); 544*967dd82fSFlorian Fainelli } 545*967dd82fSFlorian Fainelli 546*967dd82fSFlorian Fainelli static const struct b53_mib_desc *b53_get_mib(struct b53_device *dev) 547*967dd82fSFlorian Fainelli { 548*967dd82fSFlorian Fainelli if (is5365(dev)) 549*967dd82fSFlorian Fainelli return b53_mibs_65; 550*967dd82fSFlorian Fainelli else if (is63xx(dev)) 551*967dd82fSFlorian Fainelli return b53_mibs_63xx; 552*967dd82fSFlorian Fainelli else 553*967dd82fSFlorian Fainelli return b53_mibs; 554*967dd82fSFlorian Fainelli } 555*967dd82fSFlorian Fainelli 556*967dd82fSFlorian Fainelli static unsigned int b53_get_mib_size(struct b53_device *dev) 557*967dd82fSFlorian Fainelli { 558*967dd82fSFlorian Fainelli if (is5365(dev)) 559*967dd82fSFlorian Fainelli return B53_MIBS_65_SIZE; 560*967dd82fSFlorian Fainelli else if (is63xx(dev)) 561*967dd82fSFlorian Fainelli return B53_MIBS_63XX_SIZE; 562*967dd82fSFlorian Fainelli else 563*967dd82fSFlorian Fainelli return B53_MIBS_SIZE; 564*967dd82fSFlorian Fainelli } 565*967dd82fSFlorian Fainelli 566*967dd82fSFlorian Fainelli static void b53_get_strings(struct dsa_switch *ds, int port, uint8_t *data) 567*967dd82fSFlorian Fainelli { 568*967dd82fSFlorian Fainelli struct b53_device *dev = ds_to_priv(ds); 569*967dd82fSFlorian Fainelli const struct b53_mib_desc *mibs = b53_get_mib(dev); 570*967dd82fSFlorian Fainelli unsigned int mib_size = b53_get_mib_size(dev); 571*967dd82fSFlorian Fainelli unsigned int i; 572*967dd82fSFlorian Fainelli 573*967dd82fSFlorian Fainelli for (i = 0; i < mib_size; i++) 574*967dd82fSFlorian Fainelli memcpy(data + i * ETH_GSTRING_LEN, 575*967dd82fSFlorian Fainelli mibs[i].name, ETH_GSTRING_LEN); 576*967dd82fSFlorian Fainelli } 577*967dd82fSFlorian Fainelli 578*967dd82fSFlorian Fainelli static void b53_get_ethtool_stats(struct dsa_switch *ds, int port, 579*967dd82fSFlorian Fainelli uint64_t *data) 580*967dd82fSFlorian Fainelli { 581*967dd82fSFlorian Fainelli struct b53_device *dev = ds_to_priv(ds); 582*967dd82fSFlorian Fainelli const struct b53_mib_desc *mibs = b53_get_mib(dev); 583*967dd82fSFlorian Fainelli unsigned int mib_size = b53_get_mib_size(dev); 584*967dd82fSFlorian Fainelli const struct b53_mib_desc *s; 585*967dd82fSFlorian Fainelli unsigned int i; 586*967dd82fSFlorian Fainelli u64 val = 0; 587*967dd82fSFlorian Fainelli 588*967dd82fSFlorian Fainelli if (is5365(dev) && port == 5) 589*967dd82fSFlorian Fainelli port = 8; 590*967dd82fSFlorian Fainelli 591*967dd82fSFlorian Fainelli mutex_lock(&dev->stats_mutex); 592*967dd82fSFlorian Fainelli 593*967dd82fSFlorian Fainelli for (i = 0; i < mib_size; i++) { 594*967dd82fSFlorian Fainelli s = &mibs[i]; 595*967dd82fSFlorian Fainelli 596*967dd82fSFlorian Fainelli if (mibs->size == 8) { 597*967dd82fSFlorian Fainelli b53_read64(dev, B53_MIB_PAGE(port), s->offset, &val); 598*967dd82fSFlorian Fainelli } else { 599*967dd82fSFlorian Fainelli u32 val32; 600*967dd82fSFlorian Fainelli 601*967dd82fSFlorian Fainelli b53_read32(dev, B53_MIB_PAGE(port), s->offset, 602*967dd82fSFlorian Fainelli &val32); 603*967dd82fSFlorian Fainelli val = val32; 604*967dd82fSFlorian Fainelli } 605*967dd82fSFlorian Fainelli data[i] = (u64)val; 606*967dd82fSFlorian Fainelli } 607*967dd82fSFlorian Fainelli 608*967dd82fSFlorian Fainelli mutex_unlock(&dev->stats_mutex); 609*967dd82fSFlorian Fainelli } 610*967dd82fSFlorian Fainelli 611*967dd82fSFlorian Fainelli static int b53_get_sset_count(struct dsa_switch *ds) 612*967dd82fSFlorian Fainelli { 613*967dd82fSFlorian Fainelli struct b53_device *dev = ds_to_priv(ds); 614*967dd82fSFlorian Fainelli 615*967dd82fSFlorian Fainelli return b53_get_mib_size(dev); 616*967dd82fSFlorian Fainelli } 617*967dd82fSFlorian Fainelli 618*967dd82fSFlorian Fainelli static int b53_set_addr(struct dsa_switch *ds, u8 *addr) 619*967dd82fSFlorian Fainelli { 620*967dd82fSFlorian Fainelli return 0; 621*967dd82fSFlorian Fainelli } 622*967dd82fSFlorian Fainelli 623*967dd82fSFlorian Fainelli static int b53_setup(struct dsa_switch *ds) 624*967dd82fSFlorian Fainelli { 625*967dd82fSFlorian Fainelli struct b53_device *dev = ds_to_priv(ds); 626*967dd82fSFlorian Fainelli unsigned int port; 627*967dd82fSFlorian Fainelli int ret; 628*967dd82fSFlorian Fainelli 629*967dd82fSFlorian Fainelli ret = b53_reset_switch(dev); 630*967dd82fSFlorian Fainelli if (ret) { 631*967dd82fSFlorian Fainelli dev_err(ds->dev, "failed to reset switch\n"); 632*967dd82fSFlorian Fainelli return ret; 633*967dd82fSFlorian Fainelli } 634*967dd82fSFlorian Fainelli 635*967dd82fSFlorian Fainelli b53_reset_mib(dev); 636*967dd82fSFlorian Fainelli 637*967dd82fSFlorian Fainelli ret = b53_apply_config(dev); 638*967dd82fSFlorian Fainelli if (ret) 639*967dd82fSFlorian Fainelli dev_err(ds->dev, "failed to apply configuration\n"); 640*967dd82fSFlorian Fainelli 641*967dd82fSFlorian Fainelli for (port = 0; port < dev->num_ports; port++) { 642*967dd82fSFlorian Fainelli if (BIT(port) & ds->enabled_port_mask) 643*967dd82fSFlorian Fainelli b53_enable_port(ds, port, NULL); 644*967dd82fSFlorian Fainelli else if (dsa_is_cpu_port(ds, port)) 645*967dd82fSFlorian Fainelli b53_enable_cpu_port(dev); 646*967dd82fSFlorian Fainelli else 647*967dd82fSFlorian Fainelli b53_disable_port(ds, port, NULL); 648*967dd82fSFlorian Fainelli } 649*967dd82fSFlorian Fainelli 650*967dd82fSFlorian Fainelli return ret; 651*967dd82fSFlorian Fainelli } 652*967dd82fSFlorian Fainelli 653*967dd82fSFlorian Fainelli static void b53_adjust_link(struct dsa_switch *ds, int port, 654*967dd82fSFlorian Fainelli struct phy_device *phydev) 655*967dd82fSFlorian Fainelli { 656*967dd82fSFlorian Fainelli struct b53_device *dev = ds_to_priv(ds); 657*967dd82fSFlorian Fainelli u8 rgmii_ctrl = 0, reg = 0, off; 658*967dd82fSFlorian Fainelli 659*967dd82fSFlorian Fainelli if (!phy_is_pseudo_fixed_link(phydev)) 660*967dd82fSFlorian Fainelli return; 661*967dd82fSFlorian Fainelli 662*967dd82fSFlorian Fainelli /* Override the port settings */ 663*967dd82fSFlorian Fainelli if (port == dev->cpu_port) { 664*967dd82fSFlorian Fainelli off = B53_PORT_OVERRIDE_CTRL; 665*967dd82fSFlorian Fainelli reg = PORT_OVERRIDE_EN; 666*967dd82fSFlorian Fainelli } else { 667*967dd82fSFlorian Fainelli off = B53_GMII_PORT_OVERRIDE_CTRL(port); 668*967dd82fSFlorian Fainelli reg = GMII_PO_EN; 669*967dd82fSFlorian Fainelli } 670*967dd82fSFlorian Fainelli 671*967dd82fSFlorian Fainelli /* Set the link UP */ 672*967dd82fSFlorian Fainelli if (phydev->link) 673*967dd82fSFlorian Fainelli reg |= PORT_OVERRIDE_LINK; 674*967dd82fSFlorian Fainelli 675*967dd82fSFlorian Fainelli if (phydev->duplex == DUPLEX_FULL) 676*967dd82fSFlorian Fainelli reg |= PORT_OVERRIDE_FULL_DUPLEX; 677*967dd82fSFlorian Fainelli 678*967dd82fSFlorian Fainelli switch (phydev->speed) { 679*967dd82fSFlorian Fainelli case 2000: 680*967dd82fSFlorian Fainelli reg |= PORT_OVERRIDE_SPEED_2000M; 681*967dd82fSFlorian Fainelli /* fallthrough */ 682*967dd82fSFlorian Fainelli case SPEED_1000: 683*967dd82fSFlorian Fainelli reg |= PORT_OVERRIDE_SPEED_1000M; 684*967dd82fSFlorian Fainelli break; 685*967dd82fSFlorian Fainelli case SPEED_100: 686*967dd82fSFlorian Fainelli reg |= PORT_OVERRIDE_SPEED_100M; 687*967dd82fSFlorian Fainelli break; 688*967dd82fSFlorian Fainelli case SPEED_10: 689*967dd82fSFlorian Fainelli reg |= PORT_OVERRIDE_SPEED_10M; 690*967dd82fSFlorian Fainelli break; 691*967dd82fSFlorian Fainelli default: 692*967dd82fSFlorian Fainelli dev_err(ds->dev, "unknown speed: %d\n", phydev->speed); 693*967dd82fSFlorian Fainelli return; 694*967dd82fSFlorian Fainelli } 695*967dd82fSFlorian Fainelli 696*967dd82fSFlorian Fainelli /* Enable flow control on BCM5301x's CPU port */ 697*967dd82fSFlorian Fainelli if (is5301x(dev) && port == dev->cpu_port) 698*967dd82fSFlorian Fainelli reg |= PORT_OVERRIDE_RX_FLOW | PORT_OVERRIDE_TX_FLOW; 699*967dd82fSFlorian Fainelli 700*967dd82fSFlorian Fainelli if (phydev->pause) { 701*967dd82fSFlorian Fainelli if (phydev->asym_pause) 702*967dd82fSFlorian Fainelli reg |= PORT_OVERRIDE_TX_FLOW; 703*967dd82fSFlorian Fainelli reg |= PORT_OVERRIDE_RX_FLOW; 704*967dd82fSFlorian Fainelli } 705*967dd82fSFlorian Fainelli 706*967dd82fSFlorian Fainelli b53_write8(dev, B53_CTRL_PAGE, off, reg); 707*967dd82fSFlorian Fainelli 708*967dd82fSFlorian Fainelli if (is531x5(dev) && phy_interface_is_rgmii(phydev)) { 709*967dd82fSFlorian Fainelli if (port == 8) 710*967dd82fSFlorian Fainelli off = B53_RGMII_CTRL_IMP; 711*967dd82fSFlorian Fainelli else 712*967dd82fSFlorian Fainelli off = B53_RGMII_CTRL_P(port); 713*967dd82fSFlorian Fainelli 714*967dd82fSFlorian Fainelli /* Configure the port RGMII clock delay by DLL disabled and 715*967dd82fSFlorian Fainelli * tx_clk aligned timing (restoring to reset defaults) 716*967dd82fSFlorian Fainelli */ 717*967dd82fSFlorian Fainelli b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl); 718*967dd82fSFlorian Fainelli rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC | 719*967dd82fSFlorian Fainelli RGMII_CTRL_TIMING_SEL); 720*967dd82fSFlorian Fainelli 721*967dd82fSFlorian Fainelli /* PHY_INTERFACE_MODE_RGMII_TXID means TX internal delay, make 722*967dd82fSFlorian Fainelli * sure that we enable the port TX clock internal delay to 723*967dd82fSFlorian Fainelli * account for this internal delay that is inserted, otherwise 724*967dd82fSFlorian Fainelli * the switch won't be able to receive correctly. 725*967dd82fSFlorian Fainelli * 726*967dd82fSFlorian Fainelli * PHY_INTERFACE_MODE_RGMII means that we are not introducing 727*967dd82fSFlorian Fainelli * any delay neither on transmission nor reception, so the 728*967dd82fSFlorian Fainelli * BCM53125 must also be configured accordingly to account for 729*967dd82fSFlorian Fainelli * the lack of delay and introduce 730*967dd82fSFlorian Fainelli * 731*967dd82fSFlorian Fainelli * The BCM53125 switch has its RX clock and TX clock control 732*967dd82fSFlorian Fainelli * swapped, hence the reason why we modify the TX clock path in 733*967dd82fSFlorian Fainelli * the "RGMII" case 734*967dd82fSFlorian Fainelli */ 735*967dd82fSFlorian Fainelli if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 736*967dd82fSFlorian Fainelli rgmii_ctrl |= RGMII_CTRL_DLL_TXC; 737*967dd82fSFlorian Fainelli if (phydev->interface == PHY_INTERFACE_MODE_RGMII) 738*967dd82fSFlorian Fainelli rgmii_ctrl |= RGMII_CTRL_DLL_TXC | RGMII_CTRL_DLL_RXC; 739*967dd82fSFlorian Fainelli rgmii_ctrl |= RGMII_CTRL_TIMING_SEL; 740*967dd82fSFlorian Fainelli b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl); 741*967dd82fSFlorian Fainelli 742*967dd82fSFlorian Fainelli dev_info(ds->dev, "Configured port %d for %s\n", port, 743*967dd82fSFlorian Fainelli phy_modes(phydev->interface)); 744*967dd82fSFlorian Fainelli } 745*967dd82fSFlorian Fainelli 746*967dd82fSFlorian Fainelli /* configure MII port if necessary */ 747*967dd82fSFlorian Fainelli if (is5325(dev)) { 748*967dd82fSFlorian Fainelli b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, 749*967dd82fSFlorian Fainelli ®); 750*967dd82fSFlorian Fainelli 751*967dd82fSFlorian Fainelli /* reverse mii needs to be enabled */ 752*967dd82fSFlorian Fainelli if (!(reg & PORT_OVERRIDE_RV_MII_25)) { 753*967dd82fSFlorian Fainelli b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, 754*967dd82fSFlorian Fainelli reg | PORT_OVERRIDE_RV_MII_25); 755*967dd82fSFlorian Fainelli b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, 756*967dd82fSFlorian Fainelli ®); 757*967dd82fSFlorian Fainelli 758*967dd82fSFlorian Fainelli if (!(reg & PORT_OVERRIDE_RV_MII_25)) { 759*967dd82fSFlorian Fainelli dev_err(ds->dev, 760*967dd82fSFlorian Fainelli "Failed to enable reverse MII mode\n"); 761*967dd82fSFlorian Fainelli return; 762*967dd82fSFlorian Fainelli } 763*967dd82fSFlorian Fainelli } 764*967dd82fSFlorian Fainelli } else if (is5301x(dev)) { 765*967dd82fSFlorian Fainelli if (port != dev->cpu_port) { 766*967dd82fSFlorian Fainelli u8 po_reg = B53_GMII_PORT_OVERRIDE_CTRL(dev->cpu_port); 767*967dd82fSFlorian Fainelli u8 gmii_po; 768*967dd82fSFlorian Fainelli 769*967dd82fSFlorian Fainelli b53_read8(dev, B53_CTRL_PAGE, po_reg, &gmii_po); 770*967dd82fSFlorian Fainelli gmii_po |= GMII_PO_LINK | 771*967dd82fSFlorian Fainelli GMII_PO_RX_FLOW | 772*967dd82fSFlorian Fainelli GMII_PO_TX_FLOW | 773*967dd82fSFlorian Fainelli GMII_PO_EN | 774*967dd82fSFlorian Fainelli GMII_PO_SPEED_2000M; 775*967dd82fSFlorian Fainelli b53_write8(dev, B53_CTRL_PAGE, po_reg, gmii_po); 776*967dd82fSFlorian Fainelli } 777*967dd82fSFlorian Fainelli } 778*967dd82fSFlorian Fainelli } 779*967dd82fSFlorian Fainelli 780*967dd82fSFlorian Fainelli static struct dsa_switch_driver b53_switch_ops = { 781*967dd82fSFlorian Fainelli .tag_protocol = DSA_TAG_PROTO_NONE, 782*967dd82fSFlorian Fainelli .setup = b53_setup, 783*967dd82fSFlorian Fainelli .set_addr = b53_set_addr, 784*967dd82fSFlorian Fainelli .get_strings = b53_get_strings, 785*967dd82fSFlorian Fainelli .get_ethtool_stats = b53_get_ethtool_stats, 786*967dd82fSFlorian Fainelli .get_sset_count = b53_get_sset_count, 787*967dd82fSFlorian Fainelli .phy_read = b53_phy_read16, 788*967dd82fSFlorian Fainelli .phy_write = b53_phy_write16, 789*967dd82fSFlorian Fainelli .adjust_link = b53_adjust_link, 790*967dd82fSFlorian Fainelli .port_enable = b53_enable_port, 791*967dd82fSFlorian Fainelli .port_disable = b53_disable_port, 792*967dd82fSFlorian Fainelli }; 793*967dd82fSFlorian Fainelli 794*967dd82fSFlorian Fainelli struct b53_chip_data { 795*967dd82fSFlorian Fainelli u32 chip_id; 796*967dd82fSFlorian Fainelli const char *dev_name; 797*967dd82fSFlorian Fainelli u16 vlans; 798*967dd82fSFlorian Fainelli u16 enabled_ports; 799*967dd82fSFlorian Fainelli u8 cpu_port; 800*967dd82fSFlorian Fainelli u8 vta_regs[3]; 801*967dd82fSFlorian Fainelli u8 duplex_reg; 802*967dd82fSFlorian Fainelli u8 jumbo_pm_reg; 803*967dd82fSFlorian Fainelli u8 jumbo_size_reg; 804*967dd82fSFlorian Fainelli }; 805*967dd82fSFlorian Fainelli 806*967dd82fSFlorian Fainelli #define B53_VTA_REGS \ 807*967dd82fSFlorian Fainelli { B53_VT_ACCESS, B53_VT_INDEX, B53_VT_ENTRY } 808*967dd82fSFlorian Fainelli #define B53_VTA_REGS_9798 \ 809*967dd82fSFlorian Fainelli { B53_VT_ACCESS_9798, B53_VT_INDEX_9798, B53_VT_ENTRY_9798 } 810*967dd82fSFlorian Fainelli #define B53_VTA_REGS_63XX \ 811*967dd82fSFlorian Fainelli { B53_VT_ACCESS_63XX, B53_VT_INDEX_63XX, B53_VT_ENTRY_63XX } 812*967dd82fSFlorian Fainelli 813*967dd82fSFlorian Fainelli static const struct b53_chip_data b53_switch_chips[] = { 814*967dd82fSFlorian Fainelli { 815*967dd82fSFlorian Fainelli .chip_id = BCM5325_DEVICE_ID, 816*967dd82fSFlorian Fainelli .dev_name = "BCM5325", 817*967dd82fSFlorian Fainelli .vlans = 16, 818*967dd82fSFlorian Fainelli .enabled_ports = 0x1f, 819*967dd82fSFlorian Fainelli .cpu_port = B53_CPU_PORT_25, 820*967dd82fSFlorian Fainelli .duplex_reg = B53_DUPLEX_STAT_FE, 821*967dd82fSFlorian Fainelli }, 822*967dd82fSFlorian Fainelli { 823*967dd82fSFlorian Fainelli .chip_id = BCM5365_DEVICE_ID, 824*967dd82fSFlorian Fainelli .dev_name = "BCM5365", 825*967dd82fSFlorian Fainelli .vlans = 256, 826*967dd82fSFlorian Fainelli .enabled_ports = 0x1f, 827*967dd82fSFlorian Fainelli .cpu_port = B53_CPU_PORT_25, 828*967dd82fSFlorian Fainelli .duplex_reg = B53_DUPLEX_STAT_FE, 829*967dd82fSFlorian Fainelli }, 830*967dd82fSFlorian Fainelli { 831*967dd82fSFlorian Fainelli .chip_id = BCM5395_DEVICE_ID, 832*967dd82fSFlorian Fainelli .dev_name = "BCM5395", 833*967dd82fSFlorian Fainelli .vlans = 4096, 834*967dd82fSFlorian Fainelli .enabled_ports = 0x1f, 835*967dd82fSFlorian Fainelli .cpu_port = B53_CPU_PORT, 836*967dd82fSFlorian Fainelli .vta_regs = B53_VTA_REGS, 837*967dd82fSFlorian Fainelli .duplex_reg = B53_DUPLEX_STAT_GE, 838*967dd82fSFlorian Fainelli .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 839*967dd82fSFlorian Fainelli .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 840*967dd82fSFlorian Fainelli }, 841*967dd82fSFlorian Fainelli { 842*967dd82fSFlorian Fainelli .chip_id = BCM5397_DEVICE_ID, 843*967dd82fSFlorian Fainelli .dev_name = "BCM5397", 844*967dd82fSFlorian Fainelli .vlans = 4096, 845*967dd82fSFlorian Fainelli .enabled_ports = 0x1f, 846*967dd82fSFlorian Fainelli .cpu_port = B53_CPU_PORT, 847*967dd82fSFlorian Fainelli .vta_regs = B53_VTA_REGS_9798, 848*967dd82fSFlorian Fainelli .duplex_reg = B53_DUPLEX_STAT_GE, 849*967dd82fSFlorian Fainelli .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 850*967dd82fSFlorian Fainelli .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 851*967dd82fSFlorian Fainelli }, 852*967dd82fSFlorian Fainelli { 853*967dd82fSFlorian Fainelli .chip_id = BCM5398_DEVICE_ID, 854*967dd82fSFlorian Fainelli .dev_name = "BCM5398", 855*967dd82fSFlorian Fainelli .vlans = 4096, 856*967dd82fSFlorian Fainelli .enabled_ports = 0x7f, 857*967dd82fSFlorian Fainelli .cpu_port = B53_CPU_PORT, 858*967dd82fSFlorian Fainelli .vta_regs = B53_VTA_REGS_9798, 859*967dd82fSFlorian Fainelli .duplex_reg = B53_DUPLEX_STAT_GE, 860*967dd82fSFlorian Fainelli .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 861*967dd82fSFlorian Fainelli .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 862*967dd82fSFlorian Fainelli }, 863*967dd82fSFlorian Fainelli { 864*967dd82fSFlorian Fainelli .chip_id = BCM53115_DEVICE_ID, 865*967dd82fSFlorian Fainelli .dev_name = "BCM53115", 866*967dd82fSFlorian Fainelli .vlans = 4096, 867*967dd82fSFlorian Fainelli .enabled_ports = 0x1f, 868*967dd82fSFlorian Fainelli .vta_regs = B53_VTA_REGS, 869*967dd82fSFlorian Fainelli .cpu_port = B53_CPU_PORT, 870*967dd82fSFlorian Fainelli .duplex_reg = B53_DUPLEX_STAT_GE, 871*967dd82fSFlorian Fainelli .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 872*967dd82fSFlorian Fainelli .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 873*967dd82fSFlorian Fainelli }, 874*967dd82fSFlorian Fainelli { 875*967dd82fSFlorian Fainelli .chip_id = BCM53125_DEVICE_ID, 876*967dd82fSFlorian Fainelli .dev_name = "BCM53125", 877*967dd82fSFlorian Fainelli .vlans = 4096, 878*967dd82fSFlorian Fainelli .enabled_ports = 0xff, 879*967dd82fSFlorian Fainelli .cpu_port = B53_CPU_PORT, 880*967dd82fSFlorian Fainelli .vta_regs = B53_VTA_REGS, 881*967dd82fSFlorian Fainelli .duplex_reg = B53_DUPLEX_STAT_GE, 882*967dd82fSFlorian Fainelli .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 883*967dd82fSFlorian Fainelli .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 884*967dd82fSFlorian Fainelli }, 885*967dd82fSFlorian Fainelli { 886*967dd82fSFlorian Fainelli .chip_id = BCM53128_DEVICE_ID, 887*967dd82fSFlorian Fainelli .dev_name = "BCM53128", 888*967dd82fSFlorian Fainelli .vlans = 4096, 889*967dd82fSFlorian Fainelli .enabled_ports = 0x1ff, 890*967dd82fSFlorian Fainelli .cpu_port = B53_CPU_PORT, 891*967dd82fSFlorian Fainelli .vta_regs = B53_VTA_REGS, 892*967dd82fSFlorian Fainelli .duplex_reg = B53_DUPLEX_STAT_GE, 893*967dd82fSFlorian Fainelli .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 894*967dd82fSFlorian Fainelli .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 895*967dd82fSFlorian Fainelli }, 896*967dd82fSFlorian Fainelli { 897*967dd82fSFlorian Fainelli .chip_id = BCM63XX_DEVICE_ID, 898*967dd82fSFlorian Fainelli .dev_name = "BCM63xx", 899*967dd82fSFlorian Fainelli .vlans = 4096, 900*967dd82fSFlorian Fainelli .enabled_ports = 0, /* pdata must provide them */ 901*967dd82fSFlorian Fainelli .cpu_port = B53_CPU_PORT, 902*967dd82fSFlorian Fainelli .vta_regs = B53_VTA_REGS_63XX, 903*967dd82fSFlorian Fainelli .duplex_reg = B53_DUPLEX_STAT_63XX, 904*967dd82fSFlorian Fainelli .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX, 905*967dd82fSFlorian Fainelli .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX, 906*967dd82fSFlorian Fainelli }, 907*967dd82fSFlorian Fainelli { 908*967dd82fSFlorian Fainelli .chip_id = BCM53010_DEVICE_ID, 909*967dd82fSFlorian Fainelli .dev_name = "BCM53010", 910*967dd82fSFlorian Fainelli .vlans = 4096, 911*967dd82fSFlorian Fainelli .enabled_ports = 0x1f, 912*967dd82fSFlorian Fainelli .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ 913*967dd82fSFlorian Fainelli .vta_regs = B53_VTA_REGS, 914*967dd82fSFlorian Fainelli .duplex_reg = B53_DUPLEX_STAT_GE, 915*967dd82fSFlorian Fainelli .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 916*967dd82fSFlorian Fainelli .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 917*967dd82fSFlorian Fainelli }, 918*967dd82fSFlorian Fainelli { 919*967dd82fSFlorian Fainelli .chip_id = BCM53011_DEVICE_ID, 920*967dd82fSFlorian Fainelli .dev_name = "BCM53011", 921*967dd82fSFlorian Fainelli .vlans = 4096, 922*967dd82fSFlorian Fainelli .enabled_ports = 0x1bf, 923*967dd82fSFlorian Fainelli .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ 924*967dd82fSFlorian Fainelli .vta_regs = B53_VTA_REGS, 925*967dd82fSFlorian Fainelli .duplex_reg = B53_DUPLEX_STAT_GE, 926*967dd82fSFlorian Fainelli .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 927*967dd82fSFlorian Fainelli .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 928*967dd82fSFlorian Fainelli }, 929*967dd82fSFlorian Fainelli { 930*967dd82fSFlorian Fainelli .chip_id = BCM53012_DEVICE_ID, 931*967dd82fSFlorian Fainelli .dev_name = "BCM53012", 932*967dd82fSFlorian Fainelli .vlans = 4096, 933*967dd82fSFlorian Fainelli .enabled_ports = 0x1bf, 934*967dd82fSFlorian Fainelli .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ 935*967dd82fSFlorian Fainelli .vta_regs = B53_VTA_REGS, 936*967dd82fSFlorian Fainelli .duplex_reg = B53_DUPLEX_STAT_GE, 937*967dd82fSFlorian Fainelli .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 938*967dd82fSFlorian Fainelli .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 939*967dd82fSFlorian Fainelli }, 940*967dd82fSFlorian Fainelli { 941*967dd82fSFlorian Fainelli .chip_id = BCM53018_DEVICE_ID, 942*967dd82fSFlorian Fainelli .dev_name = "BCM53018", 943*967dd82fSFlorian Fainelli .vlans = 4096, 944*967dd82fSFlorian Fainelli .enabled_ports = 0x1f, 945*967dd82fSFlorian Fainelli .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ 946*967dd82fSFlorian Fainelli .vta_regs = B53_VTA_REGS, 947*967dd82fSFlorian Fainelli .duplex_reg = B53_DUPLEX_STAT_GE, 948*967dd82fSFlorian Fainelli .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 949*967dd82fSFlorian Fainelli .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 950*967dd82fSFlorian Fainelli }, 951*967dd82fSFlorian Fainelli { 952*967dd82fSFlorian Fainelli .chip_id = BCM53019_DEVICE_ID, 953*967dd82fSFlorian Fainelli .dev_name = "BCM53019", 954*967dd82fSFlorian Fainelli .vlans = 4096, 955*967dd82fSFlorian Fainelli .enabled_ports = 0x1f, 956*967dd82fSFlorian Fainelli .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ 957*967dd82fSFlorian Fainelli .vta_regs = B53_VTA_REGS, 958*967dd82fSFlorian Fainelli .duplex_reg = B53_DUPLEX_STAT_GE, 959*967dd82fSFlorian Fainelli .jumbo_pm_reg = B53_JUMBO_PORT_MASK, 960*967dd82fSFlorian Fainelli .jumbo_size_reg = B53_JUMBO_MAX_SIZE, 961*967dd82fSFlorian Fainelli }, 962*967dd82fSFlorian Fainelli }; 963*967dd82fSFlorian Fainelli 964*967dd82fSFlorian Fainelli static int b53_switch_init(struct b53_device *dev) 965*967dd82fSFlorian Fainelli { 966*967dd82fSFlorian Fainelli struct dsa_switch *ds = dev->ds; 967*967dd82fSFlorian Fainelli unsigned int i; 968*967dd82fSFlorian Fainelli int ret; 969*967dd82fSFlorian Fainelli 970*967dd82fSFlorian Fainelli for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) { 971*967dd82fSFlorian Fainelli const struct b53_chip_data *chip = &b53_switch_chips[i]; 972*967dd82fSFlorian Fainelli 973*967dd82fSFlorian Fainelli if (chip->chip_id == dev->chip_id) { 974*967dd82fSFlorian Fainelli if (!dev->enabled_ports) 975*967dd82fSFlorian Fainelli dev->enabled_ports = chip->enabled_ports; 976*967dd82fSFlorian Fainelli dev->name = chip->dev_name; 977*967dd82fSFlorian Fainelli dev->duplex_reg = chip->duplex_reg; 978*967dd82fSFlorian Fainelli dev->vta_regs[0] = chip->vta_regs[0]; 979*967dd82fSFlorian Fainelli dev->vta_regs[1] = chip->vta_regs[1]; 980*967dd82fSFlorian Fainelli dev->vta_regs[2] = chip->vta_regs[2]; 981*967dd82fSFlorian Fainelli dev->jumbo_pm_reg = chip->jumbo_pm_reg; 982*967dd82fSFlorian Fainelli ds->drv = &b53_switch_ops; 983*967dd82fSFlorian Fainelli dev->cpu_port = chip->cpu_port; 984*967dd82fSFlorian Fainelli dev->num_vlans = chip->vlans; 985*967dd82fSFlorian Fainelli break; 986*967dd82fSFlorian Fainelli } 987*967dd82fSFlorian Fainelli } 988*967dd82fSFlorian Fainelli 989*967dd82fSFlorian Fainelli /* check which BCM5325x version we have */ 990*967dd82fSFlorian Fainelli if (is5325(dev)) { 991*967dd82fSFlorian Fainelli u8 vc4; 992*967dd82fSFlorian Fainelli 993*967dd82fSFlorian Fainelli b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4); 994*967dd82fSFlorian Fainelli 995*967dd82fSFlorian Fainelli /* check reserved bits */ 996*967dd82fSFlorian Fainelli switch (vc4 & 3) { 997*967dd82fSFlorian Fainelli case 1: 998*967dd82fSFlorian Fainelli /* BCM5325E */ 999*967dd82fSFlorian Fainelli break; 1000*967dd82fSFlorian Fainelli case 3: 1001*967dd82fSFlorian Fainelli /* BCM5325F - do not use port 4 */ 1002*967dd82fSFlorian Fainelli dev->enabled_ports &= ~BIT(4); 1003*967dd82fSFlorian Fainelli break; 1004*967dd82fSFlorian Fainelli default: 1005*967dd82fSFlorian Fainelli /* On the BCM47XX SoCs this is the supported internal switch.*/ 1006*967dd82fSFlorian Fainelli #ifndef CONFIG_BCM47XX 1007*967dd82fSFlorian Fainelli /* BCM5325M */ 1008*967dd82fSFlorian Fainelli return -EINVAL; 1009*967dd82fSFlorian Fainelli #else 1010*967dd82fSFlorian Fainelli break; 1011*967dd82fSFlorian Fainelli #endif 1012*967dd82fSFlorian Fainelli } 1013*967dd82fSFlorian Fainelli } else if (dev->chip_id == BCM53115_DEVICE_ID) { 1014*967dd82fSFlorian Fainelli u64 strap_value; 1015*967dd82fSFlorian Fainelli 1016*967dd82fSFlorian Fainelli b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value); 1017*967dd82fSFlorian Fainelli /* use second IMP port if GMII is enabled */ 1018*967dd82fSFlorian Fainelli if (strap_value & SV_GMII_CTRL_115) 1019*967dd82fSFlorian Fainelli dev->cpu_port = 5; 1020*967dd82fSFlorian Fainelli } 1021*967dd82fSFlorian Fainelli 1022*967dd82fSFlorian Fainelli /* cpu port is always last */ 1023*967dd82fSFlorian Fainelli dev->num_ports = dev->cpu_port + 1; 1024*967dd82fSFlorian Fainelli dev->enabled_ports |= BIT(dev->cpu_port); 1025*967dd82fSFlorian Fainelli 1026*967dd82fSFlorian Fainelli dev->ports = devm_kzalloc(dev->dev, 1027*967dd82fSFlorian Fainelli sizeof(struct b53_port) * dev->num_ports, 1028*967dd82fSFlorian Fainelli GFP_KERNEL); 1029*967dd82fSFlorian Fainelli if (!dev->ports) 1030*967dd82fSFlorian Fainelli return -ENOMEM; 1031*967dd82fSFlorian Fainelli 1032*967dd82fSFlorian Fainelli dev->reset_gpio = b53_switch_get_reset_gpio(dev); 1033*967dd82fSFlorian Fainelli if (dev->reset_gpio >= 0) { 1034*967dd82fSFlorian Fainelli ret = devm_gpio_request_one(dev->dev, dev->reset_gpio, 1035*967dd82fSFlorian Fainelli GPIOF_OUT_INIT_HIGH, "robo_reset"); 1036*967dd82fSFlorian Fainelli if (ret) 1037*967dd82fSFlorian Fainelli return ret; 1038*967dd82fSFlorian Fainelli } 1039*967dd82fSFlorian Fainelli 1040*967dd82fSFlorian Fainelli return 0; 1041*967dd82fSFlorian Fainelli } 1042*967dd82fSFlorian Fainelli 1043*967dd82fSFlorian Fainelli struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops, 1044*967dd82fSFlorian Fainelli void *priv) 1045*967dd82fSFlorian Fainelli { 1046*967dd82fSFlorian Fainelli struct dsa_switch *ds; 1047*967dd82fSFlorian Fainelli struct b53_device *dev; 1048*967dd82fSFlorian Fainelli 1049*967dd82fSFlorian Fainelli ds = devm_kzalloc(base, sizeof(*ds) + sizeof(*dev), GFP_KERNEL); 1050*967dd82fSFlorian Fainelli if (!ds) 1051*967dd82fSFlorian Fainelli return NULL; 1052*967dd82fSFlorian Fainelli 1053*967dd82fSFlorian Fainelli dev = (struct b53_device *)(ds + 1); 1054*967dd82fSFlorian Fainelli 1055*967dd82fSFlorian Fainelli ds->priv = dev; 1056*967dd82fSFlorian Fainelli ds->dev = base; 1057*967dd82fSFlorian Fainelli dev->dev = base; 1058*967dd82fSFlorian Fainelli 1059*967dd82fSFlorian Fainelli dev->ds = ds; 1060*967dd82fSFlorian Fainelli dev->priv = priv; 1061*967dd82fSFlorian Fainelli dev->ops = ops; 1062*967dd82fSFlorian Fainelli mutex_init(&dev->reg_mutex); 1063*967dd82fSFlorian Fainelli mutex_init(&dev->stats_mutex); 1064*967dd82fSFlorian Fainelli 1065*967dd82fSFlorian Fainelli return dev; 1066*967dd82fSFlorian Fainelli } 1067*967dd82fSFlorian Fainelli EXPORT_SYMBOL(b53_switch_alloc); 1068*967dd82fSFlorian Fainelli 1069*967dd82fSFlorian Fainelli int b53_switch_detect(struct b53_device *dev) 1070*967dd82fSFlorian Fainelli { 1071*967dd82fSFlorian Fainelli u32 id32; 1072*967dd82fSFlorian Fainelli u16 tmp; 1073*967dd82fSFlorian Fainelli u8 id8; 1074*967dd82fSFlorian Fainelli int ret; 1075*967dd82fSFlorian Fainelli 1076*967dd82fSFlorian Fainelli ret = b53_read8(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id8); 1077*967dd82fSFlorian Fainelli if (ret) 1078*967dd82fSFlorian Fainelli return ret; 1079*967dd82fSFlorian Fainelli 1080*967dd82fSFlorian Fainelli switch (id8) { 1081*967dd82fSFlorian Fainelli case 0: 1082*967dd82fSFlorian Fainelli /* BCM5325 and BCM5365 do not have this register so reads 1083*967dd82fSFlorian Fainelli * return 0. But the read operation did succeed, so assume this 1084*967dd82fSFlorian Fainelli * is one of them. 1085*967dd82fSFlorian Fainelli * 1086*967dd82fSFlorian Fainelli * Next check if we can write to the 5325's VTA register; for 1087*967dd82fSFlorian Fainelli * 5365 it is read only. 1088*967dd82fSFlorian Fainelli */ 1089*967dd82fSFlorian Fainelli b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf); 1090*967dd82fSFlorian Fainelli b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp); 1091*967dd82fSFlorian Fainelli 1092*967dd82fSFlorian Fainelli if (tmp == 0xf) 1093*967dd82fSFlorian Fainelli dev->chip_id = BCM5325_DEVICE_ID; 1094*967dd82fSFlorian Fainelli else 1095*967dd82fSFlorian Fainelli dev->chip_id = BCM5365_DEVICE_ID; 1096*967dd82fSFlorian Fainelli break; 1097*967dd82fSFlorian Fainelli case BCM5395_DEVICE_ID: 1098*967dd82fSFlorian Fainelli case BCM5397_DEVICE_ID: 1099*967dd82fSFlorian Fainelli case BCM5398_DEVICE_ID: 1100*967dd82fSFlorian Fainelli dev->chip_id = id8; 1101*967dd82fSFlorian Fainelli break; 1102*967dd82fSFlorian Fainelli default: 1103*967dd82fSFlorian Fainelli ret = b53_read32(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id32); 1104*967dd82fSFlorian Fainelli if (ret) 1105*967dd82fSFlorian Fainelli return ret; 1106*967dd82fSFlorian Fainelli 1107*967dd82fSFlorian Fainelli switch (id32) { 1108*967dd82fSFlorian Fainelli case BCM53115_DEVICE_ID: 1109*967dd82fSFlorian Fainelli case BCM53125_DEVICE_ID: 1110*967dd82fSFlorian Fainelli case BCM53128_DEVICE_ID: 1111*967dd82fSFlorian Fainelli case BCM53010_DEVICE_ID: 1112*967dd82fSFlorian Fainelli case BCM53011_DEVICE_ID: 1113*967dd82fSFlorian Fainelli case BCM53012_DEVICE_ID: 1114*967dd82fSFlorian Fainelli case BCM53018_DEVICE_ID: 1115*967dd82fSFlorian Fainelli case BCM53019_DEVICE_ID: 1116*967dd82fSFlorian Fainelli dev->chip_id = id32; 1117*967dd82fSFlorian Fainelli break; 1118*967dd82fSFlorian Fainelli default: 1119*967dd82fSFlorian Fainelli pr_err("unsupported switch detected (BCM53%02x/BCM%x)\n", 1120*967dd82fSFlorian Fainelli id8, id32); 1121*967dd82fSFlorian Fainelli return -ENODEV; 1122*967dd82fSFlorian Fainelli } 1123*967dd82fSFlorian Fainelli } 1124*967dd82fSFlorian Fainelli 1125*967dd82fSFlorian Fainelli if (dev->chip_id == BCM5325_DEVICE_ID) 1126*967dd82fSFlorian Fainelli return b53_read8(dev, B53_STAT_PAGE, B53_REV_ID_25, 1127*967dd82fSFlorian Fainelli &dev->core_rev); 1128*967dd82fSFlorian Fainelli else 1129*967dd82fSFlorian Fainelli return b53_read8(dev, B53_MGMT_PAGE, B53_REV_ID, 1130*967dd82fSFlorian Fainelli &dev->core_rev); 1131*967dd82fSFlorian Fainelli } 1132*967dd82fSFlorian Fainelli EXPORT_SYMBOL(b53_switch_detect); 1133*967dd82fSFlorian Fainelli 1134*967dd82fSFlorian Fainelli int b53_switch_register(struct b53_device *dev) 1135*967dd82fSFlorian Fainelli { 1136*967dd82fSFlorian Fainelli int ret; 1137*967dd82fSFlorian Fainelli 1138*967dd82fSFlorian Fainelli if (dev->pdata) { 1139*967dd82fSFlorian Fainelli dev->chip_id = dev->pdata->chip_id; 1140*967dd82fSFlorian Fainelli dev->enabled_ports = dev->pdata->enabled_ports; 1141*967dd82fSFlorian Fainelli } 1142*967dd82fSFlorian Fainelli 1143*967dd82fSFlorian Fainelli if (!dev->chip_id && b53_switch_detect(dev)) 1144*967dd82fSFlorian Fainelli return -EINVAL; 1145*967dd82fSFlorian Fainelli 1146*967dd82fSFlorian Fainelli ret = b53_switch_init(dev); 1147*967dd82fSFlorian Fainelli if (ret) 1148*967dd82fSFlorian Fainelli return ret; 1149*967dd82fSFlorian Fainelli 1150*967dd82fSFlorian Fainelli pr_info("found switch: %s, rev %i\n", dev->name, dev->core_rev); 1151*967dd82fSFlorian Fainelli 1152*967dd82fSFlorian Fainelli return dsa_register_switch(dev->ds, dev->ds->dev->of_node); 1153*967dd82fSFlorian Fainelli } 1154*967dd82fSFlorian Fainelli EXPORT_SYMBOL(b53_switch_register); 1155*967dd82fSFlorian Fainelli 1156*967dd82fSFlorian Fainelli MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>"); 1157*967dd82fSFlorian Fainelli MODULE_DESCRIPTION("B53 switch library"); 1158*967dd82fSFlorian Fainelli MODULE_LICENSE("Dual BSD/GPL"); 1159