17330dd0bSAdrian Chadd /*- 27330dd0bSAdrian Chadd * Copyright (c) 2011-2012 Stefan Bethke. 37330dd0bSAdrian Chadd * Copyright (c) 2014 Adrian Chadd. 47330dd0bSAdrian Chadd * All rights reserved. 57330dd0bSAdrian Chadd * 67330dd0bSAdrian Chadd * Redistribution and use in source and binary forms, with or without 77330dd0bSAdrian Chadd * modification, are permitted provided that the following conditions 87330dd0bSAdrian Chadd * are met: 97330dd0bSAdrian Chadd * 1. Redistributions of source code must retain the above copyright 107330dd0bSAdrian Chadd * notice, this list of conditions and the following disclaimer. 117330dd0bSAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 127330dd0bSAdrian Chadd * notice, this list of conditions and the following disclaimer in the 137330dd0bSAdrian Chadd * documentation and/or other materials provided with the distribution. 147330dd0bSAdrian Chadd * 157330dd0bSAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 167330dd0bSAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 177330dd0bSAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 187330dd0bSAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 197330dd0bSAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 207330dd0bSAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 217330dd0bSAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 227330dd0bSAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 237330dd0bSAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 247330dd0bSAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 257330dd0bSAdrian Chadd * SUCH DAMAGE. 267330dd0bSAdrian Chadd * 277330dd0bSAdrian Chadd * $FreeBSD$ 287330dd0bSAdrian Chadd */ 297330dd0bSAdrian Chadd 307330dd0bSAdrian Chadd #include <sys/param.h> 317330dd0bSAdrian Chadd #include <sys/bus.h> 327330dd0bSAdrian Chadd #include <sys/errno.h> 337330dd0bSAdrian Chadd #include <sys/kernel.h> 347330dd0bSAdrian Chadd #include <sys/module.h> 357330dd0bSAdrian Chadd #include <sys/socket.h> 367330dd0bSAdrian Chadd #include <sys/sockio.h> 377330dd0bSAdrian Chadd #include <sys/sysctl.h> 387330dd0bSAdrian Chadd #include <sys/systm.h> 397330dd0bSAdrian Chadd 407330dd0bSAdrian Chadd #include <net/if.h> 417330dd0bSAdrian Chadd #include <net/if_arp.h> 427330dd0bSAdrian Chadd #include <net/ethernet.h> 437330dd0bSAdrian Chadd #include <net/if_dl.h> 447330dd0bSAdrian Chadd #include <net/if_media.h> 457330dd0bSAdrian Chadd #include <net/if_types.h> 467330dd0bSAdrian Chadd 477330dd0bSAdrian Chadd #include <machine/bus.h> 487330dd0bSAdrian Chadd #include <dev/iicbus/iic.h> 497330dd0bSAdrian Chadd #include <dev/iicbus/iiconf.h> 507330dd0bSAdrian Chadd #include <dev/iicbus/iicbus.h> 517330dd0bSAdrian Chadd #include <dev/mii/mii.h> 527330dd0bSAdrian Chadd #include <dev/mii/miivar.h> 537330dd0bSAdrian Chadd #include <dev/etherswitch/mdio.h> 547330dd0bSAdrian Chadd 557330dd0bSAdrian Chadd #include <dev/etherswitch/etherswitch.h> 567330dd0bSAdrian Chadd 577330dd0bSAdrian Chadd #include <dev/etherswitch/arswitch/arswitchreg.h> 587330dd0bSAdrian Chadd #include <dev/etherswitch/arswitch/arswitchvar.h> 597330dd0bSAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_reg.h> 607330dd0bSAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_8327.h> 617330dd0bSAdrian Chadd 627330dd0bSAdrian Chadd #include "mdio_if.h" 637330dd0bSAdrian Chadd #include "miibus_if.h" 647330dd0bSAdrian Chadd #include "etherswitch_if.h" 657330dd0bSAdrian Chadd 667330dd0bSAdrian Chadd static void 677330dd0bSAdrian Chadd ar8327_phy_fixup(struct arswitch_softc *sc, int phy) 687330dd0bSAdrian Chadd { 697330dd0bSAdrian Chadd 707330dd0bSAdrian Chadd switch (sc->chip_rev) { 717330dd0bSAdrian Chadd case 1: 727330dd0bSAdrian Chadd /* For 100M waveform */ 737330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0, 0x02ea); 747330dd0bSAdrian Chadd /* Turn on Gigabit clock */ 757330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0x3d, 0x68a0); 767330dd0bSAdrian Chadd break; 777330dd0bSAdrian Chadd 787330dd0bSAdrian Chadd case 2: 797330dd0bSAdrian Chadd arswitch_writemmd(sc->sc_dev, phy, 0x7, 0x3c); 807330dd0bSAdrian Chadd arswitch_writemmd(sc->sc_dev, phy, 0x4007, 0x0); 817330dd0bSAdrian Chadd /* fallthrough */ 827330dd0bSAdrian Chadd case 4: 837330dd0bSAdrian Chadd arswitch_writemmd(sc->sc_dev, phy, 0x3, 0x800d); 847330dd0bSAdrian Chadd arswitch_writemmd(sc->sc_dev, phy, 0x4003, 0x803f); 857330dd0bSAdrian Chadd 867330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0x3d, 0x6860); 877330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0x5, 0x2c46); 887330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0x3c, 0x6000); 897330dd0bSAdrian Chadd break; 907330dd0bSAdrian Chadd } 917330dd0bSAdrian Chadd } 927330dd0bSAdrian Chadd 937330dd0bSAdrian Chadd static uint32_t 947330dd0bSAdrian Chadd ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg) 957330dd0bSAdrian Chadd { 967330dd0bSAdrian Chadd uint32_t t; 977330dd0bSAdrian Chadd 987330dd0bSAdrian Chadd if (!cfg) 997330dd0bSAdrian Chadd return (0); 1007330dd0bSAdrian Chadd 1017330dd0bSAdrian Chadd t = 0; 1027330dd0bSAdrian Chadd switch (cfg->mode) { 1037330dd0bSAdrian Chadd case AR8327_PAD_NC: 1047330dd0bSAdrian Chadd break; 1057330dd0bSAdrian Chadd 1067330dd0bSAdrian Chadd case AR8327_PAD_MAC2MAC_MII: 1077330dd0bSAdrian Chadd t = AR8327_PAD_MAC_MII_EN; 1087330dd0bSAdrian Chadd if (cfg->rxclk_sel) 1097330dd0bSAdrian Chadd t |= AR8327_PAD_MAC_MII_RXCLK_SEL; 1107330dd0bSAdrian Chadd if (cfg->txclk_sel) 1117330dd0bSAdrian Chadd t |= AR8327_PAD_MAC_MII_TXCLK_SEL; 1127330dd0bSAdrian Chadd break; 1137330dd0bSAdrian Chadd 1147330dd0bSAdrian Chadd case AR8327_PAD_MAC2MAC_GMII: 1157330dd0bSAdrian Chadd t = AR8327_PAD_MAC_GMII_EN; 1167330dd0bSAdrian Chadd if (cfg->rxclk_sel) 1177330dd0bSAdrian Chadd t |= AR8327_PAD_MAC_GMII_RXCLK_SEL; 1187330dd0bSAdrian Chadd if (cfg->txclk_sel) 1197330dd0bSAdrian Chadd t |= AR8327_PAD_MAC_GMII_TXCLK_SEL; 1207330dd0bSAdrian Chadd break; 1217330dd0bSAdrian Chadd 1227330dd0bSAdrian Chadd case AR8327_PAD_MAC_SGMII: 1237330dd0bSAdrian Chadd t = AR8327_PAD_SGMII_EN; 1247330dd0bSAdrian Chadd 1257330dd0bSAdrian Chadd /* 1269ab21e32SAdrian Chadd * WAR for the Qualcomm Atheros AP136 board. 1277330dd0bSAdrian Chadd * It seems that RGMII TX/RX delay settings needs to be 1287330dd0bSAdrian Chadd * applied for SGMII mode as well, The ethernet is not 1297330dd0bSAdrian Chadd * reliable without this. 1307330dd0bSAdrian Chadd */ 1317330dd0bSAdrian Chadd t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; 1327330dd0bSAdrian Chadd t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; 1337330dd0bSAdrian Chadd if (cfg->rxclk_delay_en) 1347330dd0bSAdrian Chadd t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; 1357330dd0bSAdrian Chadd if (cfg->txclk_delay_en) 1367330dd0bSAdrian Chadd t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; 1377330dd0bSAdrian Chadd 1387330dd0bSAdrian Chadd if (cfg->sgmii_delay_en) 1397330dd0bSAdrian Chadd t |= AR8327_PAD_SGMII_DELAY_EN; 1407330dd0bSAdrian Chadd 1417330dd0bSAdrian Chadd break; 1427330dd0bSAdrian Chadd 1437330dd0bSAdrian Chadd case AR8327_PAD_MAC2PHY_MII: 1447330dd0bSAdrian Chadd t = AR8327_PAD_PHY_MII_EN; 1457330dd0bSAdrian Chadd if (cfg->rxclk_sel) 1467330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_MII_RXCLK_SEL; 1477330dd0bSAdrian Chadd if (cfg->txclk_sel) 1487330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_MII_TXCLK_SEL; 1497330dd0bSAdrian Chadd break; 1507330dd0bSAdrian Chadd 1517330dd0bSAdrian Chadd case AR8327_PAD_MAC2PHY_GMII: 1527330dd0bSAdrian Chadd t = AR8327_PAD_PHY_GMII_EN; 1537330dd0bSAdrian Chadd if (cfg->pipe_rxclk_sel) 1547330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL; 1557330dd0bSAdrian Chadd if (cfg->rxclk_sel) 1567330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_GMII_RXCLK_SEL; 1577330dd0bSAdrian Chadd if (cfg->txclk_sel) 1587330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_GMII_TXCLK_SEL; 1597330dd0bSAdrian Chadd break; 1607330dd0bSAdrian Chadd 1617330dd0bSAdrian Chadd case AR8327_PAD_MAC_RGMII: 1627330dd0bSAdrian Chadd t = AR8327_PAD_RGMII_EN; 1637330dd0bSAdrian Chadd t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; 1647330dd0bSAdrian Chadd t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; 1657330dd0bSAdrian Chadd if (cfg->rxclk_delay_en) 1667330dd0bSAdrian Chadd t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; 1677330dd0bSAdrian Chadd if (cfg->txclk_delay_en) 1687330dd0bSAdrian Chadd t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; 1697330dd0bSAdrian Chadd break; 1707330dd0bSAdrian Chadd 1717330dd0bSAdrian Chadd case AR8327_PAD_PHY_GMII: 1727330dd0bSAdrian Chadd t = AR8327_PAD_PHYX_GMII_EN; 1737330dd0bSAdrian Chadd break; 1747330dd0bSAdrian Chadd 1757330dd0bSAdrian Chadd case AR8327_PAD_PHY_RGMII: 1767330dd0bSAdrian Chadd t = AR8327_PAD_PHYX_RGMII_EN; 1777330dd0bSAdrian Chadd break; 1787330dd0bSAdrian Chadd 1797330dd0bSAdrian Chadd case AR8327_PAD_PHY_MII: 1807330dd0bSAdrian Chadd t = AR8327_PAD_PHYX_MII_EN; 1817330dd0bSAdrian Chadd break; 1827330dd0bSAdrian Chadd } 1837330dd0bSAdrian Chadd 1847330dd0bSAdrian Chadd return (t); 1857330dd0bSAdrian Chadd } 1867330dd0bSAdrian Chadd 1877330dd0bSAdrian Chadd /* 1887330dd0bSAdrian Chadd * Map the hard-coded port config from the switch setup to 1897330dd0bSAdrian Chadd * the chipset port config (status, duplex, flow, etc.) 1907330dd0bSAdrian Chadd */ 1917330dd0bSAdrian Chadd static uint32_t 1927330dd0bSAdrian Chadd ar8327_get_port_init_status(struct ar8327_port_cfg *cfg) 1937330dd0bSAdrian Chadd { 1947330dd0bSAdrian Chadd uint32_t t; 1957330dd0bSAdrian Chadd 1967330dd0bSAdrian Chadd if (!cfg->force_link) 1977330dd0bSAdrian Chadd return (AR8X16_PORT_STS_LINK_AUTO); 1987330dd0bSAdrian Chadd 1997330dd0bSAdrian Chadd t = AR8X16_PORT_STS_TXMAC | AR8X16_PORT_STS_RXMAC; 2007330dd0bSAdrian Chadd t |= cfg->duplex ? AR8X16_PORT_STS_DUPLEX : 0; 2017330dd0bSAdrian Chadd t |= cfg->rxpause ? AR8X16_PORT_STS_RXFLOW : 0; 2027330dd0bSAdrian Chadd t |= cfg->txpause ? AR8X16_PORT_STS_TXFLOW : 0; 2037330dd0bSAdrian Chadd 2047330dd0bSAdrian Chadd switch (cfg->speed) { 2057330dd0bSAdrian Chadd case AR8327_PORT_SPEED_10: 2067330dd0bSAdrian Chadd t |= AR8X16_PORT_STS_SPEED_10; 2077330dd0bSAdrian Chadd break; 2087330dd0bSAdrian Chadd case AR8327_PORT_SPEED_100: 2097330dd0bSAdrian Chadd t |= AR8X16_PORT_STS_SPEED_100; 2107330dd0bSAdrian Chadd break; 2117330dd0bSAdrian Chadd case AR8327_PORT_SPEED_1000: 2127330dd0bSAdrian Chadd t |= AR8X16_PORT_STS_SPEED_1000; 2137330dd0bSAdrian Chadd break; 2147330dd0bSAdrian Chadd } 2157330dd0bSAdrian Chadd 2167330dd0bSAdrian Chadd return (t); 2177330dd0bSAdrian Chadd } 2189ab21e32SAdrian Chadd 2199ab21e32SAdrian Chadd /* 220*f9950f9aSAdrian Chadd * Fetch the port data for the given port. 221*f9950f9aSAdrian Chadd * 222*f9950f9aSAdrian Chadd * This goes and does dirty things with the hints space 223*f9950f9aSAdrian Chadd * to determine what the configuration parameters should be. 224*f9950f9aSAdrian Chadd * 225*f9950f9aSAdrian Chadd * Returns 1 if the structure was successfully parsed and 226*f9950f9aSAdrian Chadd * the contents are valid; 0 otherwise. 227*f9950f9aSAdrian Chadd */ 228*f9950f9aSAdrian Chadd static int 229*f9950f9aSAdrian Chadd ar8327_fetch_pdata_port(struct arswitch_softc *sc, 230*f9950f9aSAdrian Chadd struct ar8327_port_cfg *pcfg, 231*f9950f9aSAdrian Chadd int port) 232*f9950f9aSAdrian Chadd { 233*f9950f9aSAdrian Chadd int val; 234*f9950f9aSAdrian Chadd char sbuf[128]; 235*f9950f9aSAdrian Chadd 236*f9950f9aSAdrian Chadd /* Check if force_link exists */ 237*f9950f9aSAdrian Chadd val = 0; 238*f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.force_link", port); 239*f9950f9aSAdrian Chadd (void) resource_int_value(device_get_name(sc->sc_dev), 240*f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 241*f9950f9aSAdrian Chadd sbuf, &val); 242*f9950f9aSAdrian Chadd if (val != 1) 243*f9950f9aSAdrian Chadd return (0); 244*f9950f9aSAdrian Chadd pcfg->force_link = 1; 245*f9950f9aSAdrian Chadd 246*f9950f9aSAdrian Chadd /* force_link is set; let's parse the rest of the fields */ 247*f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.speed", port); 248*f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 249*f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 250*f9950f9aSAdrian Chadd sbuf, &val) == 0) { 251*f9950f9aSAdrian Chadd switch (val) { 252*f9950f9aSAdrian Chadd case 10: 253*f9950f9aSAdrian Chadd pcfg->speed = AR8327_PORT_SPEED_10; 254*f9950f9aSAdrian Chadd break; 255*f9950f9aSAdrian Chadd case 100: 256*f9950f9aSAdrian Chadd pcfg->speed = AR8327_PORT_SPEED_100; 257*f9950f9aSAdrian Chadd break; 258*f9950f9aSAdrian Chadd case 1000: 259*f9950f9aSAdrian Chadd pcfg->speed = AR8327_PORT_SPEED_1000; 260*f9950f9aSAdrian Chadd break; 261*f9950f9aSAdrian Chadd default: 262*f9950f9aSAdrian Chadd device_printf(sc->sc_dev, 263*f9950f9aSAdrian Chadd "%s: invalid port %d duplex value (%d)\n", 264*f9950f9aSAdrian Chadd __func__, 265*f9950f9aSAdrian Chadd port, 266*f9950f9aSAdrian Chadd val); 267*f9950f9aSAdrian Chadd return (0); 268*f9950f9aSAdrian Chadd } 269*f9950f9aSAdrian Chadd } 270*f9950f9aSAdrian Chadd 271*f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.duplex", port); 272*f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 273*f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 274*f9950f9aSAdrian Chadd sbuf, &val) == 0) 275*f9950f9aSAdrian Chadd pcfg->duplex = val; 276*f9950f9aSAdrian Chadd 277*f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.txpause", port); 278*f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 279*f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 280*f9950f9aSAdrian Chadd sbuf, &val) == 0) 281*f9950f9aSAdrian Chadd pcfg->txpause = val; 282*f9950f9aSAdrian Chadd 283*f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.rxpause", port); 284*f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 285*f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 286*f9950f9aSAdrian Chadd sbuf, &val) == 0) 287*f9950f9aSAdrian Chadd pcfg->rxpause = val; 288*f9950f9aSAdrian Chadd 289*f9950f9aSAdrian Chadd #if 0 290*f9950f9aSAdrian Chadd device_printf(sc->sc_dev, 291*f9950f9aSAdrian Chadd "%s: port %d: speed=%d, duplex=%d, txpause=%d, rxpause=%d\n", 292*f9950f9aSAdrian Chadd __func__, 293*f9950f9aSAdrian Chadd port, 294*f9950f9aSAdrian Chadd pcfg->speed, 295*f9950f9aSAdrian Chadd pcfg->duplex, 296*f9950f9aSAdrian Chadd pcfg->txpause, 297*f9950f9aSAdrian Chadd pcfg->rxpause); 298*f9950f9aSAdrian Chadd #endif 299*f9950f9aSAdrian Chadd 300*f9950f9aSAdrian Chadd return (1); 301*f9950f9aSAdrian Chadd } 302*f9950f9aSAdrian Chadd 303*f9950f9aSAdrian Chadd /* 304*f9950f9aSAdrian Chadd * Parse the pad configuration from the boot hints. 305*f9950f9aSAdrian Chadd * 306*f9950f9aSAdrian Chadd * The (mostly optional) fields are: 307*f9950f9aSAdrian Chadd * 308*f9950f9aSAdrian Chadd * uint32_t mode; 309*f9950f9aSAdrian Chadd * uint32_t rxclk_sel; 310*f9950f9aSAdrian Chadd * uint32_t txclk_sel; 311*f9950f9aSAdrian Chadd * uint32_t txclk_delay_sel; 312*f9950f9aSAdrian Chadd * uint32_t rxclk_delay_sel; 313*f9950f9aSAdrian Chadd * uint32_t txclk_delay_en; 314*f9950f9aSAdrian Chadd * uint32_t rxclk_delay_en; 315*f9950f9aSAdrian Chadd * uint32_t sgmii_delay_en; 316*f9950f9aSAdrian Chadd * uint32_t pipe_rxclk_sel; 317*f9950f9aSAdrian Chadd * 318*f9950f9aSAdrian Chadd * If mode isn't in the hints, 0 is returned. 319*f9950f9aSAdrian Chadd * Else the structure is fleshed out and 1 is returned. 320*f9950f9aSAdrian Chadd */ 321*f9950f9aSAdrian Chadd static int 322*f9950f9aSAdrian Chadd ar8327_fetch_pdata_pad(struct arswitch_softc *sc, 323*f9950f9aSAdrian Chadd struct ar8327_pad_cfg *pc, 324*f9950f9aSAdrian Chadd int pad) 325*f9950f9aSAdrian Chadd { 326*f9950f9aSAdrian Chadd int val; 327*f9950f9aSAdrian Chadd char sbuf[128]; 328*f9950f9aSAdrian Chadd 329*f9950f9aSAdrian Chadd /* Check if mode exists */ 330*f9950f9aSAdrian Chadd val = 0; 331*f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.mode", pad); 332*f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 333*f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 334*f9950f9aSAdrian Chadd sbuf, &val) != 0) 335*f9950f9aSAdrian Chadd return (0); 336*f9950f9aSAdrian Chadd 337*f9950f9aSAdrian Chadd /* assume that 'mode' exists and was found */ 338*f9950f9aSAdrian Chadd pc->mode = val; 339*f9950f9aSAdrian Chadd 340*f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.rxclk_sel", pad); 341*f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 342*f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 343*f9950f9aSAdrian Chadd sbuf, &val) == 0) 344*f9950f9aSAdrian Chadd pc->rxclk_sel = val; 345*f9950f9aSAdrian Chadd 346*f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.txclk_sel", pad); 347*f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 348*f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 349*f9950f9aSAdrian Chadd sbuf, &val) == 0) 350*f9950f9aSAdrian Chadd pc->txclk_sel = val; 351*f9950f9aSAdrian Chadd 352*f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.txclk_delay_sel", pad); 353*f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 354*f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 355*f9950f9aSAdrian Chadd sbuf, &val) == 0) 356*f9950f9aSAdrian Chadd pc->txclk_delay_sel = val; 357*f9950f9aSAdrian Chadd 358*f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.rxclk_delay_sel", pad); 359*f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 360*f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 361*f9950f9aSAdrian Chadd sbuf, &val) == 0) 362*f9950f9aSAdrian Chadd pc->rxclk_delay_sel = val; 363*f9950f9aSAdrian Chadd 364*f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.txclk_delay_en", pad); 365*f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 366*f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 367*f9950f9aSAdrian Chadd sbuf, &val) == 0) 368*f9950f9aSAdrian Chadd pc->txclk_delay_en = val; 369*f9950f9aSAdrian Chadd 370*f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.rxclk_delay_en", pad); 371*f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 372*f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 373*f9950f9aSAdrian Chadd sbuf, &val) == 0) 374*f9950f9aSAdrian Chadd pc->rxclk_delay_en = val; 375*f9950f9aSAdrian Chadd 376*f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.sgmii_delay_en", pad); 377*f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 378*f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 379*f9950f9aSAdrian Chadd sbuf, &val) == 0) 380*f9950f9aSAdrian Chadd pc->sgmii_delay_en = val; 381*f9950f9aSAdrian Chadd 382*f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.pipe_rxclk_sel", pad); 383*f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 384*f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 385*f9950f9aSAdrian Chadd sbuf, &val) == 0) 386*f9950f9aSAdrian Chadd pc->pipe_rxclk_sel = val; 387*f9950f9aSAdrian Chadd 388*f9950f9aSAdrian Chadd #if 0 389*f9950f9aSAdrian Chadd device_printf(sc->sc_dev, 390*f9950f9aSAdrian Chadd "%s: pad %d: mode=%d, rxclk_sel=%d, txclk_sel=%d, " 391*f9950f9aSAdrian Chadd "txclk_delay_sel=%d, rxclk_delay_sel=%d, txclk_delay_en=%d, " 392*f9950f9aSAdrian Chadd "rxclk_enable_en=%d, sgmii_delay_en=%d, pipe_rxclk_sel=%d\n", 393*f9950f9aSAdrian Chadd __func__, 394*f9950f9aSAdrian Chadd pad, 395*f9950f9aSAdrian Chadd pc->mode, 396*f9950f9aSAdrian Chadd pc->rxclk_sel, 397*f9950f9aSAdrian Chadd pc->txclk_sel, 398*f9950f9aSAdrian Chadd pc->txclk_delay_sel, 399*f9950f9aSAdrian Chadd pc->rxclk_delay_sel, 400*f9950f9aSAdrian Chadd pc->txclk_delay_en, 401*f9950f9aSAdrian Chadd pc->rxclk_delay_en, 402*f9950f9aSAdrian Chadd pc->sgmii_delay_en, 403*f9950f9aSAdrian Chadd pc->pipe_rxclk_sel); 404*f9950f9aSAdrian Chadd #endif 405*f9950f9aSAdrian Chadd 406*f9950f9aSAdrian Chadd return (1); 407*f9950f9aSAdrian Chadd } 408*f9950f9aSAdrian Chadd 409*f9950f9aSAdrian Chadd /* 4109ab21e32SAdrian Chadd * Initialise the ar8327 specific hardware features from 4119ab21e32SAdrian Chadd * the hints provided in the boot environment. 4129ab21e32SAdrian Chadd */ 4139ab21e32SAdrian Chadd static int 4149ab21e32SAdrian Chadd ar8327_init_pdata(struct arswitch_softc *sc) 4159ab21e32SAdrian Chadd { 4169ab21e32SAdrian Chadd struct ar8327_pad_cfg pc; 4179ab21e32SAdrian Chadd struct ar8327_port_cfg port_cfg; 4189ab21e32SAdrian Chadd uint32_t t; 4199ab21e32SAdrian Chadd 420*f9950f9aSAdrian Chadd /* Port 0 */ 4219ab21e32SAdrian Chadd bzero(&port_cfg, sizeof(port_cfg)); 422*f9950f9aSAdrian Chadd sc->ar8327.port0_status = 0; 423*f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_port(sc, &port_cfg, 0)) 4249ab21e32SAdrian Chadd sc->ar8327.port0_status = ar8327_get_port_init_status(&port_cfg); 4259ab21e32SAdrian Chadd 426*f9950f9aSAdrian Chadd /* Port 6 */ 4279ab21e32SAdrian Chadd bzero(&port_cfg, sizeof(port_cfg)); 428*f9950f9aSAdrian Chadd sc->ar8327.port6_status = 0; 429*f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_port(sc, &port_cfg, 6)) 4309ab21e32SAdrian Chadd sc->ar8327.port6_status = ar8327_get_port_init_status(&port_cfg); 4319ab21e32SAdrian Chadd 4329ab21e32SAdrian Chadd /* Pad 0 */ 4339ab21e32SAdrian Chadd bzero(&pc, sizeof(pc)); 434*f9950f9aSAdrian Chadd t = 0; 435*f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_pad(sc, &pc, 0)) 4369ab21e32SAdrian Chadd t = ar8327_get_pad_cfg(&pc); 4379ab21e32SAdrian Chadd #if 0 4389ab21e32SAdrian Chadd if (AR8X16_IS_SWITCH(sc, AR8337)) 4399ab21e32SAdrian Chadd t |= AR8337_PAD_MAC06_EXCHANGE_EN; 4407330dd0bSAdrian Chadd #endif 4419ab21e32SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PAD0_MODE, t); 4429ab21e32SAdrian Chadd 4439ab21e32SAdrian Chadd /* Pad 5 */ 4449ab21e32SAdrian Chadd bzero(&pc, sizeof(pc)); 445*f9950f9aSAdrian Chadd t = 0; 446*f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_pad(sc, &pc, 5)) 4479ab21e32SAdrian Chadd t = ar8327_get_pad_cfg(&pc); 4489ab21e32SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PAD5_MODE, t); 4499ab21e32SAdrian Chadd 4509ab21e32SAdrian Chadd /* Pad 6 */ 4519ab21e32SAdrian Chadd bzero(&pc, sizeof(pc)); 452*f9950f9aSAdrian Chadd t = 0; 453*f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_pad(sc, &pc, 6)) 4549ab21e32SAdrian Chadd t = ar8327_get_pad_cfg(&pc); 4559ab21e32SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PAD6_MODE, t); 4569ab21e32SAdrian Chadd 4579ab21e32SAdrian Chadd /* XXX LED config */ 4589ab21e32SAdrian Chadd 4599ab21e32SAdrian Chadd /* XXX SGMII config */ 4609ab21e32SAdrian Chadd 4619ab21e32SAdrian Chadd return (0); 4629ab21e32SAdrian Chadd } 4637330dd0bSAdrian Chadd 4647330dd0bSAdrian Chadd static int 4657330dd0bSAdrian Chadd ar8327_hw_setup(struct arswitch_softc *sc) 4667330dd0bSAdrian Chadd { 4677330dd0bSAdrian Chadd int i; 4687330dd0bSAdrian Chadd int err; 4697330dd0bSAdrian Chadd 4707330dd0bSAdrian Chadd /* pdata fetch and setup */ 4717330dd0bSAdrian Chadd err = ar8327_init_pdata(sc); 4727330dd0bSAdrian Chadd if (err != 0) 4737330dd0bSAdrian Chadd return (err); 4747330dd0bSAdrian Chadd 4757330dd0bSAdrian Chadd /* XXX init leds */ 4767330dd0bSAdrian Chadd 4777330dd0bSAdrian Chadd for (i = 0; i < AR8327_NUM_PHYS; i++) { 4787330dd0bSAdrian Chadd /* phy fixup */ 4797330dd0bSAdrian Chadd ar8327_phy_fixup(sc, i); 4807330dd0bSAdrian Chadd 4817330dd0bSAdrian Chadd /* start PHY autonegotiation? */ 4827330dd0bSAdrian Chadd /* XXX is this done as part of the normal PHY setup? */ 4837330dd0bSAdrian Chadd 4847330dd0bSAdrian Chadd }; 4857330dd0bSAdrian Chadd 4867330dd0bSAdrian Chadd /* Let things settle */ 4877330dd0bSAdrian Chadd DELAY(1000); 4887330dd0bSAdrian Chadd 4897330dd0bSAdrian Chadd return (0); 4907330dd0bSAdrian Chadd } 4917330dd0bSAdrian Chadd 4927330dd0bSAdrian Chadd /* 4937330dd0bSAdrian Chadd * Initialise other global values, for the AR8327. 4947330dd0bSAdrian Chadd */ 4957330dd0bSAdrian Chadd static int 4967330dd0bSAdrian Chadd ar8327_hw_global_setup(struct arswitch_softc *sc) 4977330dd0bSAdrian Chadd { 4987330dd0bSAdrian Chadd uint32_t t; 4997330dd0bSAdrian Chadd 5007330dd0bSAdrian Chadd /* enable CPU port and disable mirror port */ 5017330dd0bSAdrian Chadd t = AR8327_FWD_CTRL0_CPU_PORT_EN | 5027330dd0bSAdrian Chadd AR8327_FWD_CTRL0_MIRROR_PORT; 5037330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_FWD_CTRL0, t); 5047330dd0bSAdrian Chadd 5057330dd0bSAdrian Chadd /* forward multicast and broadcast frames to CPU */ 5067330dd0bSAdrian Chadd t = (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_UC_FLOOD_S) | 5077330dd0bSAdrian Chadd (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_MC_FLOOD_S) | 5087330dd0bSAdrian Chadd (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_BC_FLOOD_S); 5097330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_FWD_CTRL1, t); 5107330dd0bSAdrian Chadd 5117330dd0bSAdrian Chadd /* enable jumbo frames */ 5127330dd0bSAdrian Chadd /* XXX need to macro-shift the value! */ 5137330dd0bSAdrian Chadd arswitch_modifyreg(sc->sc_dev, AR8327_REG_MAX_FRAME_SIZE, 5147330dd0bSAdrian Chadd AR8327_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2); 5157330dd0bSAdrian Chadd 5167330dd0bSAdrian Chadd /* Enable MIB counters */ 5177330dd0bSAdrian Chadd arswitch_modifyreg(sc->sc_dev, AR8327_REG_MODULE_EN, 5187330dd0bSAdrian Chadd AR8327_MODULE_EN_MIB, AR8327_MODULE_EN_MIB); 5197330dd0bSAdrian Chadd 5207330dd0bSAdrian Chadd return (0); 5217330dd0bSAdrian Chadd } 5227330dd0bSAdrian Chadd 5237330dd0bSAdrian Chadd /* 5247330dd0bSAdrian Chadd * Port setup. 5257330dd0bSAdrian Chadd */ 5267330dd0bSAdrian Chadd static void 5277330dd0bSAdrian Chadd ar8327_port_init(struct arswitch_softc *sc, int port) 5287330dd0bSAdrian Chadd { 5297330dd0bSAdrian Chadd uint32_t t; 5307330dd0bSAdrian Chadd 5319ab21e32SAdrian Chadd if (port == AR8X16_PORT_CPU) 5329ab21e32SAdrian Chadd t = sc->ar8327.port0_status; 5337330dd0bSAdrian Chadd else if (port == 6) 5349ab21e32SAdrian Chadd t = sc->ar8327.port6_status; 5357330dd0bSAdrian Chadd else 5369ab21e32SAdrian Chadd #if 0 5377330dd0bSAdrian Chadd /* XXX DB120 - hard-code port0 to 1000/full */ 5387330dd0bSAdrian Chadd if (port == 0) { 5397330dd0bSAdrian Chadd t = AR8X16_PORT_STS_SPEED_1000; 5407330dd0bSAdrian Chadd t |= AR8X16_PORT_STS_TXMAC | AR8X16_PORT_STS_RXMAC; 5417330dd0bSAdrian Chadd t |= AR8X16_PORT_STS_DUPLEX; 5427330dd0bSAdrian Chadd t |= AR8X16_PORT_STS_RXFLOW; 5437330dd0bSAdrian Chadd t |= AR8X16_PORT_STS_TXFLOW; 5447330dd0bSAdrian Chadd } else 5459ab21e32SAdrian Chadd #endif 5467330dd0bSAdrian Chadd t = AR8X16_PORT_STS_LINK_AUTO; 5477330dd0bSAdrian Chadd 5487330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_STATUS(port), t); 5497330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_HEADER(port), 0); 5507330dd0bSAdrian Chadd 5517330dd0bSAdrian Chadd t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S; 5527330dd0bSAdrian Chadd t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S; 5537330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN0(port), t); 5547330dd0bSAdrian Chadd 5557330dd0bSAdrian Chadd t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S; 5567330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN1(port), t); 5577330dd0bSAdrian Chadd 5587330dd0bSAdrian Chadd t = AR8327_PORT_LOOKUP_LEARN; 5597330dd0bSAdrian Chadd t |= AR8X16_PORT_CTRL_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; 5607330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(port), t); 5617330dd0bSAdrian Chadd } 5627330dd0bSAdrian Chadd 5637330dd0bSAdrian Chadd static int 5647330dd0bSAdrian Chadd ar8327_port_vlan_setup(struct arswitch_softc *sc, etherswitch_port_t *p) 5657330dd0bSAdrian Chadd { 5667330dd0bSAdrian Chadd 5677330dd0bSAdrian Chadd /* XXX stub for now */ 5687330dd0bSAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 5697330dd0bSAdrian Chadd return (0); 5707330dd0bSAdrian Chadd } 5717330dd0bSAdrian Chadd 5727330dd0bSAdrian Chadd static int 5737330dd0bSAdrian Chadd ar8327_port_vlan_get(struct arswitch_softc *sc, etherswitch_port_t *p) 5747330dd0bSAdrian Chadd { 5757330dd0bSAdrian Chadd 5767330dd0bSAdrian Chadd /* XXX stub for now */ 5777330dd0bSAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 5787330dd0bSAdrian Chadd return (0); 5797330dd0bSAdrian Chadd } 5807330dd0bSAdrian Chadd 5817330dd0bSAdrian Chadd static void 5827330dd0bSAdrian Chadd ar8327_reset_vlans(struct arswitch_softc *sc) 5837330dd0bSAdrian Chadd { 5847330dd0bSAdrian Chadd int i; 5857330dd0bSAdrian Chadd uint32_t mode, t; 5867330dd0bSAdrian Chadd 5877330dd0bSAdrian Chadd /* 5887330dd0bSAdrian Chadd * For now, let's default to one portgroup, just so traffic 5897330dd0bSAdrian Chadd * flows. All ports can see other ports. 5907330dd0bSAdrian Chadd */ 5917330dd0bSAdrian Chadd for (i = 0; i < AR8327_NUM_PORTS; i++) { 5927330dd0bSAdrian Chadd /* set pvid = i */ 5937330dd0bSAdrian Chadd t = i << AR8327_PORT_VLAN0_DEF_SVID_S; 5947330dd0bSAdrian Chadd t |= i << AR8327_PORT_VLAN0_DEF_CVID_S; 5957330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN0(i), t); 5967330dd0bSAdrian Chadd 5977330dd0bSAdrian Chadd /* set egress == out_keep */ 5987330dd0bSAdrian Chadd mode = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH; 5997330dd0bSAdrian Chadd 6007330dd0bSAdrian Chadd t = AR8327_PORT_VLAN1_PORT_VLAN_PROP; 6017330dd0bSAdrian Chadd t |= mode << AR8327_PORT_VLAN1_OUT_MODE_S; 6027330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN1(i), t); 6037330dd0bSAdrian Chadd 6047330dd0bSAdrian Chadd /* Set ingress = out_keep; members = 0x3f for all ports */ 6057330dd0bSAdrian Chadd 6067330dd0bSAdrian Chadd t = 0x3f; /* all ports */ 6077330dd0bSAdrian Chadd t |= AR8327_PORT_LOOKUP_LEARN; 6087330dd0bSAdrian Chadd 6097330dd0bSAdrian Chadd /* in_port_only, forward */ 6107330dd0bSAdrian Chadd t |= AR8X16_PORT_VLAN_MODE_PORT_ONLY << AR8327_PORT_LOOKUP_IN_MODE_S; 6117330dd0bSAdrian Chadd t |= AR8X16_PORT_CTRL_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; 6127330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(i), t); 6137330dd0bSAdrian Chadd } 6147330dd0bSAdrian Chadd } 6157330dd0bSAdrian Chadd 6167330dd0bSAdrian Chadd static int 6177330dd0bSAdrian Chadd ar8327_vlan_getvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg) 6187330dd0bSAdrian Chadd { 6197330dd0bSAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 6207330dd0bSAdrian Chadd return (0); 6217330dd0bSAdrian Chadd } 6227330dd0bSAdrian Chadd 6237330dd0bSAdrian Chadd static int 6247330dd0bSAdrian Chadd ar8327_vlan_setvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg) 6257330dd0bSAdrian Chadd { 6267330dd0bSAdrian Chadd 6277330dd0bSAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 6287330dd0bSAdrian Chadd return (0); 6297330dd0bSAdrian Chadd } 6307330dd0bSAdrian Chadd 6317330dd0bSAdrian Chadd static int 6327330dd0bSAdrian Chadd ar8327_get_pvid(struct arswitch_softc *sc, int port, int *pvid) 6337330dd0bSAdrian Chadd { 6347330dd0bSAdrian Chadd 6357330dd0bSAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 6367330dd0bSAdrian Chadd return (0); 6377330dd0bSAdrian Chadd } 6387330dd0bSAdrian Chadd 6397330dd0bSAdrian Chadd static int 6407330dd0bSAdrian Chadd ar8327_set_pvid(struct arswitch_softc *sc, int port, int pvid) 6417330dd0bSAdrian Chadd { 6427330dd0bSAdrian Chadd 6437330dd0bSAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 6447330dd0bSAdrian Chadd return (0); 6457330dd0bSAdrian Chadd } 6467330dd0bSAdrian Chadd 6477330dd0bSAdrian Chadd void 6487330dd0bSAdrian Chadd ar8327_attach(struct arswitch_softc *sc) 6497330dd0bSAdrian Chadd { 6507330dd0bSAdrian Chadd 6517330dd0bSAdrian Chadd sc->hal.arswitch_hw_setup = ar8327_hw_setup; 6527330dd0bSAdrian Chadd sc->hal.arswitch_hw_global_setup = ar8327_hw_global_setup; 6537330dd0bSAdrian Chadd 6547330dd0bSAdrian Chadd sc->hal.arswitch_port_init = ar8327_port_init; 6557330dd0bSAdrian Chadd sc->hal.arswitch_port_vlan_setup = ar8327_port_vlan_setup; 6567330dd0bSAdrian Chadd sc->hal.arswitch_port_vlan_get = ar8327_port_vlan_get; 6577330dd0bSAdrian Chadd 6587330dd0bSAdrian Chadd sc->hal.arswitch_vlan_init_hw = ar8327_reset_vlans; 6597330dd0bSAdrian Chadd sc->hal.arswitch_vlan_getvgroup = ar8327_vlan_getvgroup; 6607330dd0bSAdrian Chadd sc->hal.arswitch_vlan_setvgroup = ar8327_vlan_setvgroup; 6617330dd0bSAdrian Chadd sc->hal.arswitch_vlan_get_pvid = ar8327_get_pvid; 6627330dd0bSAdrian Chadd sc->hal.arswitch_vlan_set_pvid = ar8327_set_pvid; 6637330dd0bSAdrian Chadd 6647330dd0bSAdrian Chadd /* Set the switch vlan capabilities. */ 6657330dd0bSAdrian Chadd sc->info.es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q | 6667330dd0bSAdrian Chadd ETHERSWITCH_VLAN_PORT | ETHERSWITCH_VLAN_DOUBLE_TAG; 6677330dd0bSAdrian Chadd sc->info.es_nvlangroups = AR8X16_MAX_VLANS; 6687330dd0bSAdrian Chadd } 669