1299910Ssgalabov/*- 2299910Ssgalabov * Copyright (c) 2016 Stanislav Galabov. 3299910Ssgalabov * All rights reserved. 4299910Ssgalabov * 5299910Ssgalabov * Redistribution and use in source and binary forms, with or without 6299910Ssgalabov * modification, are permitted provided that the following conditions 7299910Ssgalabov * are met: 8299910Ssgalabov * 1. Redistributions of source code must retain the above copyright 9299910Ssgalabov * notice, this list of conditions and the following disclaimer. 10299910Ssgalabov * 2. Redistributions in binary form must reproduce the above copyright 11299910Ssgalabov * notice, this list of conditions and the following disclaimer in the 12299910Ssgalabov * documentation and/or other materials provided with the distribution. 13299910Ssgalabov * 14299910Ssgalabov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15299910Ssgalabov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16299910Ssgalabov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17299910Ssgalabov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18299910Ssgalabov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19299910Ssgalabov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20299910Ssgalabov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21299910Ssgalabov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22299910Ssgalabov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23299910Ssgalabov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24299910Ssgalabov * SUCH DAMAGE. 25299910Ssgalabov * 26299910Ssgalabov * $FreeBSD: releng/11.0/sys/dev/etherswitch/mtkswitch/mtkswitch_rt3050.c 299910 2016-05-16 07:00:49Z sgalabov $ 27299910Ssgalabov */ 28299910Ssgalabov 29299910Ssgalabov#include <sys/param.h> 30299910Ssgalabov#include <sys/bus.h> 31299910Ssgalabov#include <sys/errno.h> 32299910Ssgalabov#include <sys/kernel.h> 33299910Ssgalabov#include <sys/lock.h> 34299910Ssgalabov#include <sys/malloc.h> 35299910Ssgalabov#include <sys/module.h> 36299910Ssgalabov#include <sys/mutex.h> 37299910Ssgalabov#include <sys/rman.h> 38299910Ssgalabov#include <sys/socket.h> 39299910Ssgalabov#include <sys/sockio.h> 40299910Ssgalabov#include <sys/sysctl.h> 41299910Ssgalabov#include <sys/systm.h> 42299910Ssgalabov 43299910Ssgalabov#include <net/if.h> 44299910Ssgalabov#include <net/if_var.h> 45299910Ssgalabov#include <net/ethernet.h> 46299910Ssgalabov#include <net/if_media.h> 47299910Ssgalabov#include <net/if_types.h> 48299910Ssgalabov 49299910Ssgalabov#include <machine/bus.h> 50299910Ssgalabov#include <dev/mii/mii.h> 51299910Ssgalabov#include <dev/mii/miivar.h> 52299910Ssgalabov#include <dev/mdio/mdio.h> 53299910Ssgalabov 54299910Ssgalabov#include <dev/etherswitch/etherswitch.h> 55299910Ssgalabov#include <dev/etherswitch/mtkswitch/mtkswitchvar.h> 56299910Ssgalabov#include <dev/etherswitch/mtkswitch/mtkswitch_rt3050.h> 57299910Ssgalabov 58299910Ssgalabovstatic int 59299910Ssgalabovmtkswitch_reg_read(device_t dev, int reg) 60299910Ssgalabov{ 61299910Ssgalabov struct mtkswitch_softc *sc = device_get_softc(dev); 62299910Ssgalabov uint32_t val; 63299910Ssgalabov 64299910Ssgalabov MTKSWITCH_LOCK_ASSERT(sc, MA_OWNED); 65299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_REG32(reg)); 66299910Ssgalabov if (MTKSWITCH_IS_HI16(reg)) 67299910Ssgalabov return (MTKSWITCH_HI16(val)); 68299910Ssgalabov return (MTKSWITCH_LO16(val)); 69299910Ssgalabov} 70299910Ssgalabov 71299910Ssgalabovstatic int 72299910Ssgalabovmtkswitch_reg_write(device_t dev, int reg, int val) 73299910Ssgalabov{ 74299910Ssgalabov struct mtkswitch_softc *sc = device_get_softc(dev); 75299910Ssgalabov uint32_t tmp; 76299910Ssgalabov 77299910Ssgalabov MTKSWITCH_LOCK_ASSERT(sc, MA_OWNED); 78299910Ssgalabov tmp = MTKSWITCH_READ(sc, MTKSWITCH_REG32(reg)); 79299910Ssgalabov if (MTKSWITCH_IS_HI16(reg)) { 80299910Ssgalabov tmp &= MTKSWITCH_LO16_MSK; 81299910Ssgalabov tmp |= MTKSWITCH_TO_HI16(val); 82299910Ssgalabov } else { 83299910Ssgalabov tmp &= MTKSWITCH_HI16_MSK; 84299910Ssgalabov tmp |= MTKSWITCH_TO_LO16(val); 85299910Ssgalabov } 86299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_REG32(reg), tmp); 87299910Ssgalabov 88299910Ssgalabov return (0); 89299910Ssgalabov} 90299910Ssgalabov 91299910Ssgalabovstatic int 92299910Ssgalabovmtkswitch_phy_read(device_t dev, int phy, int reg) 93299910Ssgalabov{ 94299910Ssgalabov struct mtkswitch_softc *sc = device_get_softc(dev); 95299910Ssgalabov int val; 96299910Ssgalabov 97299910Ssgalabov MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 98299910Ssgalabov MTKSWITCH_LOCK(sc); 99299910Ssgalabov while (MTKSWITCH_READ(sc, MTKSWITCH_PCR0) & PCR0_ACTIVE); 100299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_PCR0, PCR0_READ | PCR0_REG(reg) | 101299910Ssgalabov PCR0_PHY(phy)); 102299910Ssgalabov while (MTKSWITCH_READ(sc, MTKSWITCH_PCR0) & PCR0_ACTIVE); 103299910Ssgalabov val = (MTKSWITCH_READ(sc, MTKSWITCH_PCR1) >> PCR1_DATA_OFF) & 104299910Ssgalabov PCR1_DATA_MASK; 105299910Ssgalabov MTKSWITCH_UNLOCK(sc); 106299910Ssgalabov return (val); 107299910Ssgalabov} 108299910Ssgalabov 109299910Ssgalabovstatic int 110299910Ssgalabovmtkswitch_phy_write(device_t dev, int phy, int reg, int val) 111299910Ssgalabov{ 112299910Ssgalabov struct mtkswitch_softc *sc = device_get_softc(dev); 113299910Ssgalabov 114299910Ssgalabov MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 115299910Ssgalabov MTKSWITCH_LOCK(sc); 116299910Ssgalabov while (MTKSWITCH_READ(sc, MTKSWITCH_PCR0) & PCR0_ACTIVE); 117299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_PCR0, PCR0_WRITE | PCR0_REG(reg) | 118299910Ssgalabov PCR0_PHY(phy) | PCR0_DATA(val)); 119299910Ssgalabov while (MTKSWITCH_READ(sc, MTKSWITCH_PCR0) & PCR0_ACTIVE); 120299910Ssgalabov MTKSWITCH_UNLOCK(sc); 121299910Ssgalabov return (0); 122299910Ssgalabov} 123299910Ssgalabov 124299910Ssgalabovstatic int 125299910Ssgalabovmtkswitch_reset(struct mtkswitch_softc *sc) 126299910Ssgalabov{ 127299910Ssgalabov 128299910Ssgalabov MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 129299910Ssgalabov MTKSWITCH_LOCK(sc); 130299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_STRT, STRT_RESET); 131299910Ssgalabov while (MTKSWITCH_READ(sc, MTKSWITCH_STRT) != 0); 132299910Ssgalabov MTKSWITCH_UNLOCK(sc); 133299910Ssgalabov 134299910Ssgalabov return (0); 135299910Ssgalabov} 136299910Ssgalabov 137299910Ssgalabovstatic int 138299910Ssgalabovmtkswitch_hw_setup(struct mtkswitch_softc *sc) 139299910Ssgalabov{ 140299910Ssgalabov 141299910Ssgalabov /* 142299910Ssgalabov * TODO: parse the device tree and see if we need to configure 143299910Ssgalabov * ports, etc. differently. For now we fallback to defaults. 144299910Ssgalabov */ 145299910Ssgalabov 146299910Ssgalabov /* Called early and hence unlocked */ 147299910Ssgalabov /* Set ports 0-4 to auto negotiation */ 148299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_FPA, FPA_ALL_AUTO); 149299910Ssgalabov 150299910Ssgalabov return (0); 151299910Ssgalabov} 152299910Ssgalabov 153299910Ssgalabovstatic int 154299910Ssgalabovmtkswitch_hw_global_setup(struct mtkswitch_softc *sc) 155299910Ssgalabov{ 156299910Ssgalabov 157299910Ssgalabov /* Called early and hence unlocked */ 158299910Ssgalabov return (0); 159299910Ssgalabov} 160299910Ssgalabov 161299910Ssgalabovstatic void 162299910Ssgalabovmtkswitch_port_init(struct mtkswitch_softc *sc, int port) 163299910Ssgalabov{ 164299910Ssgalabov /* Called early and hence unlocked */ 165299910Ssgalabov /* Do nothing - ports are set to auto negotiation in hw_setup */ 166299910Ssgalabov} 167299910Ssgalabov 168299910Ssgalabovstatic uint32_t 169299910Ssgalabovmtkswitch_get_port_status(struct mtkswitch_softc *sc, int port) 170299910Ssgalabov{ 171299910Ssgalabov uint32_t val, res; 172299910Ssgalabov 173299910Ssgalabov MTKSWITCH_LOCK_ASSERT(sc, MA_OWNED); 174299910Ssgalabov res = 0; 175299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_POA); 176299910Ssgalabov 177299910Ssgalabov if (val & POA_PRT_LINK(port)) 178299910Ssgalabov res |= MTKSWITCH_LINK_UP; 179299910Ssgalabov if (val & POA_PRT_DPX(port)) 180299910Ssgalabov res |= MTKSWITCH_DUPLEX; 181299910Ssgalabov 182299910Ssgalabov if (MTKSWITCH_PORT_IS_100M(port)) { 183299910Ssgalabov if (val & POA_FE_SPEED(port)) 184299910Ssgalabov res |= MTKSWITCH_SPEED_100; 185299910Ssgalabov if (val & POA_FE_XFC(port)) 186299910Ssgalabov res |= (MTKSWITCH_TXFLOW | MTKSWITCH_RXFLOW); 187299910Ssgalabov } else { 188299910Ssgalabov switch (POA_GE_SPEED(val, port)) { 189299910Ssgalabov case POA_GE_SPEED_10: 190299910Ssgalabov res |= MTKSWITCH_SPEED_10; 191299910Ssgalabov break; 192299910Ssgalabov case POA_GE_SPEED_100: 193299910Ssgalabov res |= MTKSWITCH_SPEED_100; 194299910Ssgalabov break; 195299910Ssgalabov case POA_GE_SPEED_1000: 196299910Ssgalabov res |= MTKSWITCH_SPEED_1000; 197299910Ssgalabov break; 198299910Ssgalabov } 199299910Ssgalabov 200299910Ssgalabov val = POA_GE_XFC(val, port); 201299910Ssgalabov if (val & POA_GE_XFC_TX_MSK) 202299910Ssgalabov res |= MTKSWITCH_TXFLOW; 203299910Ssgalabov if (val & POA_GE_XFC_RX_MSK) 204299910Ssgalabov res |= MTKSWITCH_RXFLOW; 205299910Ssgalabov } 206299910Ssgalabov 207299910Ssgalabov return (res); 208299910Ssgalabov} 209299910Ssgalabov 210299910Ssgalabovstatic int 211299910Ssgalabovmtkswitch_atu_flush(struct mtkswitch_softc *sc) 212299910Ssgalabov{ 213299910Ssgalabov return (0); 214299910Ssgalabov} 215299910Ssgalabov 216299910Ssgalabovstatic int 217299910Ssgalabovmtkswitch_port_vlan_setup(struct mtkswitch_softc *sc, etherswitch_port_t *p) 218299910Ssgalabov{ 219299910Ssgalabov uint32_t val; 220299910Ssgalabov int err, invert = 0; 221299910Ssgalabov 222299910Ssgalabov MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 223299910Ssgalabov MTKSWITCH_LOCK(sc); 224299910Ssgalabov /* Set the PVID. */ 225299910Ssgalabov if (p->es_pvid != 0) { 226299910Ssgalabov err = sc->hal.mtkswitch_vlan_set_pvid(sc, p->es_port, 227299910Ssgalabov p->es_pvid); 228299910Ssgalabov if (err != 0) { 229299910Ssgalabov MTKSWITCH_UNLOCK(sc); 230299910Ssgalabov return (err); 231299910Ssgalabov } 232299910Ssgalabov } 233299910Ssgalabov 234299910Ssgalabov /* Mutually exclusive */ 235299910Ssgalabov if (p->es_flags & ETHERSWITCH_PORT_ADDTAG && 236299910Ssgalabov p->es_flags & ETHERSWITCH_PORT_STRIPTAG) { 237299910Ssgalabov invert = 1; 238299910Ssgalabov } 239299910Ssgalabov 240299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_SGC2); 241299910Ssgalabov if (p->es_flags & ETHERSWITCH_PORT_DOUBLE_TAG) 242299910Ssgalabov val |= SGC2_DOUBLE_TAG_PORT(p->es_port); 243299910Ssgalabov else 244299910Ssgalabov val &= ~SGC2_DOUBLE_TAG_PORT(p->es_port); 245299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_SGC2, val); 246299910Ssgalabov 247299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_POC2); 248299910Ssgalabov if (invert) { 249299910Ssgalabov if (val & POC2_UNTAG_PORT(p->es_port)) 250299910Ssgalabov val &= ~POC2_UNTAG_PORT(p->es_port); 251299910Ssgalabov else 252299910Ssgalabov val |= POC2_UNTAG_PORT(p->es_port); 253299910Ssgalabov } else if (p->es_flags & ETHERSWITCH_PORT_STRIPTAG) 254299910Ssgalabov val |= POC2_UNTAG_PORT(p->es_port); 255299910Ssgalabov else 256299910Ssgalabov val &= ~POC2_UNTAG_PORT(p->es_port); 257299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_POC2, val); 258299910Ssgalabov MTKSWITCH_UNLOCK(sc); 259299910Ssgalabov 260299910Ssgalabov return (0); 261299910Ssgalabov} 262299910Ssgalabov 263299910Ssgalabovstatic int 264299910Ssgalabovmtkswitch_port_vlan_get(struct mtkswitch_softc *sc, etherswitch_port_t *p) 265299910Ssgalabov{ 266299910Ssgalabov uint32_t val; 267299910Ssgalabov 268299910Ssgalabov MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 269299910Ssgalabov MTKSWITCH_LOCK(sc); 270299910Ssgalabov 271299910Ssgalabov /* Retrieve the PVID */ 272299910Ssgalabov sc->hal.mtkswitch_vlan_get_pvid(sc, p->es_port, &p->es_pvid); 273299910Ssgalabov 274299910Ssgalabov /* Port flags */ 275299910Ssgalabov p->es_flags = 0; 276299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_SGC2); 277299910Ssgalabov if (val & SGC2_DOUBLE_TAG_PORT(p->es_port)) 278299910Ssgalabov p->es_flags |= ETHERSWITCH_PORT_DOUBLE_TAG; 279299910Ssgalabov 280299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_POC2); 281299910Ssgalabov if (val & POC2_UNTAG_PORT(p->es_port)) 282299910Ssgalabov p->es_flags |= ETHERSWITCH_PORT_STRIPTAG; 283299910Ssgalabov else 284299910Ssgalabov p->es_flags |= ETHERSWITCH_PORT_ADDTAG; 285299910Ssgalabov 286299910Ssgalabov MTKSWITCH_UNLOCK(sc); 287299910Ssgalabov 288299910Ssgalabov return (0); 289299910Ssgalabov} 290299910Ssgalabov 291299910Ssgalabovstatic void 292299910Ssgalabovmtkswitch_vlan_init_hw(struct mtkswitch_softc *sc) 293299910Ssgalabov{ 294299910Ssgalabov uint32_t val, vid; 295299910Ssgalabov int i; 296299910Ssgalabov 297299910Ssgalabov MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 298299910Ssgalabov MTKSWITCH_LOCK(sc); 299299910Ssgalabov 300299910Ssgalabov /* Reset everything to defaults first */ 301299910Ssgalabov for (i = 0; i < sc->info.es_nvlangroups; i++) { 302299910Ssgalabov /* Remove all VLAN members and untag info, if any */ 303299910Ssgalabov if (i % 4 == 0) { 304299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_VMSC(i), 0); 305299910Ssgalabov if (sc->sc_switchtype != MTK_SWITCH_RT3050) 306299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_VUB(i), 0); 307299910Ssgalabov } 308299910Ssgalabov /* Reset to default VIDs */ 309299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_VLANI(i)); 310299910Ssgalabov val &= ~(VLANI_MASK << VLANI_OFF(i)); 311299910Ssgalabov val |= ((i + 1) << VLANI_OFF(i)); 312299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_VLANI(i), val); 313299910Ssgalabov } 314299910Ssgalabov 315299910Ssgalabov /* Now, add all ports as untagged members to VLAN1 */ 316299910Ssgalabov vid = 0; 317299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_VMSC(vid)); 318299910Ssgalabov val &= ~(VMSC_MASK << VMSC_OFF(vid)); 319299910Ssgalabov val |= (((1<<sc->numports)-1) << VMSC_OFF(vid)); 320299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_VMSC(vid), val); 321299910Ssgalabov if (sc->sc_switchtype != MTK_SWITCH_RT3050) { 322299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_VUB(vid)); 323299910Ssgalabov val &= ~(VUB_MASK << VUB_OFF(vid)); 324299910Ssgalabov val |= (((1<<sc->numports)-1) << VUB_OFF(vid)); 325299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_VUB(vid), val); 326299910Ssgalabov } 327299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_POC2); 328299910Ssgalabov if (sc->sc_switchtype != MTK_SWITCH_RT3050) 329299910Ssgalabov val |= POC2_UNTAG_VLAN; 330299910Ssgalabov val |= ((1<<sc->numports)-1); 331299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_POC2, val); 332299910Ssgalabov 333299910Ssgalabov /* only the first vlangroup is valid */ 334299910Ssgalabov sc->valid_vlans = (1<<0); 335299910Ssgalabov 336299910Ssgalabov /* Set all port PVIDs to 1 */ 337299910Ssgalabov vid = 1; 338299910Ssgalabov for (i = 0; i < sc->info.es_nports; i++) { 339299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_PVID(i)); 340299910Ssgalabov val &= ~(PVID_MASK << PVID_OFF(i)); 341299910Ssgalabov val |= (vid << PVID_OFF(i)); 342299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_PVID(i), val); 343299910Ssgalabov } 344299910Ssgalabov 345299910Ssgalabov MTKSWITCH_UNLOCK(sc); 346299910Ssgalabov} 347299910Ssgalabov 348299910Ssgalabovstatic int 349299910Ssgalabovmtkswitch_vlan_getvgroup(struct mtkswitch_softc *sc, etherswitch_vlangroup_t *v) 350299910Ssgalabov{ 351299910Ssgalabov uint32_t val; 352299910Ssgalabov 353299910Ssgalabov MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 354299910Ssgalabov 355299910Ssgalabov if ((sc->vlan_mode != ETHERSWITCH_VLAN_DOT1Q) || 356299910Ssgalabov (v->es_vlangroup > sc->info.es_nvlangroups)) 357299910Ssgalabov return (EINVAL); 358299910Ssgalabov 359299910Ssgalabov /* Reset the member ports. */ 360299910Ssgalabov v->es_untagged_ports = 0; 361299910Ssgalabov v->es_member_ports = 0; 362299910Ssgalabov 363299910Ssgalabov /* Not supported */ 364299910Ssgalabov v->es_fid = 0; 365299910Ssgalabov 366299910Ssgalabov /* Vlan ID */ 367299910Ssgalabov v->es_vid = 0; 368299910Ssgalabov if ((sc->valid_vlans & (1<<v->es_vlangroup)) == 0) 369299910Ssgalabov return (0); 370299910Ssgalabov 371299910Ssgalabov MTKSWITCH_LOCK(sc); 372299910Ssgalabov v->es_vid = (MTKSWITCH_READ(sc, MTKSWITCH_VLANI(v->es_vlangroup)) >> 373299910Ssgalabov VLANI_OFF(v->es_vlangroup)) & VLANI_MASK; 374299910Ssgalabov v->es_vid |= ETHERSWITCH_VID_VALID; 375299910Ssgalabov 376299910Ssgalabov /* Member ports */ 377299910Ssgalabov v->es_member_ports = v->es_untagged_ports = 378299910Ssgalabov (MTKSWITCH_READ(sc, MTKSWITCH_VMSC(v->es_vlangroup)) >> 379299910Ssgalabov VMSC_OFF(v->es_vlangroup)) & VMSC_MASK; 380299910Ssgalabov 381299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_POC2); 382299910Ssgalabov 383299910Ssgalabov if ((val & POC2_UNTAG_VLAN) && sc->sc_switchtype != MTK_SWITCH_RT3050) { 384299910Ssgalabov val = (MTKSWITCH_READ(sc, MTKSWITCH_VUB(v->es_vlangroup)) >> 385299910Ssgalabov VUB_OFF(v->es_vlangroup)) & VUB_MASK; 386299910Ssgalabov } else { 387299910Ssgalabov val &= VUB_MASK; 388299910Ssgalabov } 389299910Ssgalabov v->es_untagged_ports &= val; 390299910Ssgalabov 391299910Ssgalabov MTKSWITCH_UNLOCK(sc); 392299910Ssgalabov return (0); 393299910Ssgalabov} 394299910Ssgalabov 395299910Ssgalabovstatic int 396299910Ssgalabovmtkswitch_vlan_setvgroup(struct mtkswitch_softc *sc, etherswitch_vlangroup_t *v) 397299910Ssgalabov{ 398299910Ssgalabov uint32_t val, tmp; 399299910Ssgalabov 400299910Ssgalabov if ((sc->vlan_mode != ETHERSWITCH_VLAN_DOT1Q) || 401299910Ssgalabov (v->es_vlangroup > sc->info.es_nvlangroups)) 402299910Ssgalabov return (EINVAL); 403299910Ssgalabov 404299910Ssgalabov MTKSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 405299910Ssgalabov MTKSWITCH_LOCK(sc); 406299910Ssgalabov /* First, see if we can accomodate the request at all */ 407299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_POC2); 408299910Ssgalabov if ((val & POC2_UNTAG_VLAN) == 0 || 409299910Ssgalabov sc->sc_switchtype == MTK_SWITCH_RT3050) { 410299910Ssgalabov val &= VUB_MASK; 411299910Ssgalabov tmp = v->es_untagged_ports & v->es_member_ports; 412299910Ssgalabov if (val != tmp) { 413299910Ssgalabov /* Cannot accomodate request */ 414299910Ssgalabov MTKSWITCH_UNLOCK(sc); 415299910Ssgalabov return (ENOTSUP); 416299910Ssgalabov } 417299910Ssgalabov } else { 418299910Ssgalabov /* Prefer per-Vlan untag and set its members */ 419299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_VUB(v->es_vlangroup)); 420299910Ssgalabov val &= ~(VUB_MASK << VUB_OFF(v->es_vlangroup)); 421299910Ssgalabov val |= (((v->es_untagged_ports) & VUB_MASK) << 422299910Ssgalabov VUB_OFF(v->es_vlangroup)); 423299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_VUB(v->es_vlangroup), val); 424299910Ssgalabov } 425299910Ssgalabov 426299910Ssgalabov /* Set VID */ 427299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_VLANI(v->es_vlangroup)); 428299910Ssgalabov val &= ~(VLANI_MASK << VLANI_OFF(v->es_vlangroup)); 429299910Ssgalabov val |= (v->es_vid & VLANI_MASK) << VLANI_OFF(v->es_vlangroup); 430299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_VLANI(v->es_vlangroup), val); 431299910Ssgalabov 432299910Ssgalabov /* Set members */ 433299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_VMSC(v->es_vlangroup)); 434299910Ssgalabov val &= ~(VMSC_MASK << VMSC_OFF(v->es_vlangroup)); 435299910Ssgalabov val |= (v->es_member_ports << VMSC_OFF(v->es_vlangroup)); 436299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_VMSC(v->es_vlangroup), val); 437299910Ssgalabov 438299910Ssgalabov sc->valid_vlans |= (1<<v->es_vlangroup); 439299910Ssgalabov 440299910Ssgalabov MTKSWITCH_UNLOCK(sc); 441299910Ssgalabov return (0); 442299910Ssgalabov} 443299910Ssgalabov 444299910Ssgalabovstatic int 445299910Ssgalabovmtkswitch_vlan_get_pvid(struct mtkswitch_softc *sc, int port, int *pvid) 446299910Ssgalabov{ 447299910Ssgalabov 448299910Ssgalabov MTKSWITCH_LOCK_ASSERT(sc, MA_OWNED); 449299910Ssgalabov *pvid = (MTKSWITCH_READ(sc, MTKSWITCH_PVID(port)) >> PVID_OFF(port)) & 450299910Ssgalabov PVID_MASK; 451299910Ssgalabov 452299910Ssgalabov return (0); 453299910Ssgalabov} 454299910Ssgalabov 455299910Ssgalabovstatic int 456299910Ssgalabovmtkswitch_vlan_set_pvid(struct mtkswitch_softc *sc, int port, int pvid) 457299910Ssgalabov{ 458299910Ssgalabov uint32_t val; 459299910Ssgalabov 460299910Ssgalabov MTKSWITCH_LOCK_ASSERT(sc, MA_OWNED); 461299910Ssgalabov val = MTKSWITCH_READ(sc, MTKSWITCH_PVID(port)); 462299910Ssgalabov val &= ~(PVID_MASK << PVID_OFF(port)); 463299910Ssgalabov val |= (pvid & PVID_MASK) << PVID_OFF(port); 464299910Ssgalabov MTKSWITCH_WRITE(sc, MTKSWITCH_PVID(port), val); 465299910Ssgalabov 466299910Ssgalabov return (0); 467299910Ssgalabov} 468299910Ssgalabov 469299910Ssgalabovextern void 470299910Ssgalabovmtk_attach_switch_rt3050(struct mtkswitch_softc *sc) 471299910Ssgalabov{ 472299910Ssgalabov 473299910Ssgalabov sc->portmap = 0x7f; 474299910Ssgalabov sc->phymap = 0x1f; 475299910Ssgalabov 476299910Ssgalabov sc->info.es_nports = 7; 477299910Ssgalabov sc->info.es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q; 478299910Ssgalabov sc->info.es_nvlangroups = 16; 479299910Ssgalabov sprintf(sc->info.es_name, "Ralink ESW"); 480299910Ssgalabov 481299910Ssgalabov sc->hal.mtkswitch_reset = mtkswitch_reset; 482299910Ssgalabov sc->hal.mtkswitch_hw_setup = mtkswitch_hw_setup; 483299910Ssgalabov sc->hal.mtkswitch_hw_global_setup = mtkswitch_hw_global_setup; 484299910Ssgalabov sc->hal.mtkswitch_port_init = mtkswitch_port_init; 485299910Ssgalabov sc->hal.mtkswitch_get_port_status = mtkswitch_get_port_status; 486299910Ssgalabov sc->hal.mtkswitch_atu_flush = mtkswitch_atu_flush; 487299910Ssgalabov sc->hal.mtkswitch_port_vlan_setup = mtkswitch_port_vlan_setup; 488299910Ssgalabov sc->hal.mtkswitch_port_vlan_get = mtkswitch_port_vlan_get; 489299910Ssgalabov sc->hal.mtkswitch_vlan_init_hw = mtkswitch_vlan_init_hw; 490299910Ssgalabov sc->hal.mtkswitch_vlan_getvgroup = mtkswitch_vlan_getvgroup; 491299910Ssgalabov sc->hal.mtkswitch_vlan_setvgroup = mtkswitch_vlan_setvgroup; 492299910Ssgalabov sc->hal.mtkswitch_vlan_get_pvid = mtkswitch_vlan_get_pvid; 493299910Ssgalabov sc->hal.mtkswitch_vlan_set_pvid = mtkswitch_vlan_set_pvid; 494299910Ssgalabov sc->hal.mtkswitch_phy_read = mtkswitch_phy_read; 495299910Ssgalabov sc->hal.mtkswitch_phy_write = mtkswitch_phy_write; 496299910Ssgalabov sc->hal.mtkswitch_reg_read = mtkswitch_reg_read; 497299910Ssgalabov sc->hal.mtkswitch_reg_write = mtkswitch_reg_write; 498299910Ssgalabov} 499