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> 48efce3748SRui Paulo #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 { 69*db37238fSAdrian Chadd if (bootverbose) 70*db37238fSAdrian Chadd device_printf(sc->sc_dev, 71*db37238fSAdrian Chadd "%s: called; phy=%d; chiprev=%d\n", __func__, 72*db37238fSAdrian Chadd phy, 73*db37238fSAdrian Chadd sc->chip_rev); 747330dd0bSAdrian Chadd switch (sc->chip_rev) { 757330dd0bSAdrian Chadd case 1: 767330dd0bSAdrian Chadd /* For 100M waveform */ 777330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0, 0x02ea); 787330dd0bSAdrian Chadd /* Turn on Gigabit clock */ 797330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0x3d, 0x68a0); 807330dd0bSAdrian Chadd break; 817330dd0bSAdrian Chadd 827330dd0bSAdrian Chadd case 2: 837330dd0bSAdrian Chadd arswitch_writemmd(sc->sc_dev, phy, 0x7, 0x3c); 847330dd0bSAdrian Chadd arswitch_writemmd(sc->sc_dev, phy, 0x4007, 0x0); 857330dd0bSAdrian Chadd /* fallthrough */ 867330dd0bSAdrian Chadd case 4: 877330dd0bSAdrian Chadd arswitch_writemmd(sc->sc_dev, phy, 0x3, 0x800d); 887330dd0bSAdrian Chadd arswitch_writemmd(sc->sc_dev, phy, 0x4003, 0x803f); 897330dd0bSAdrian Chadd 907330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0x3d, 0x6860); 917330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0x5, 0x2c46); 927330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0x3c, 0x6000); 937330dd0bSAdrian Chadd break; 947330dd0bSAdrian Chadd } 957330dd0bSAdrian Chadd } 967330dd0bSAdrian Chadd 977330dd0bSAdrian Chadd static uint32_t 987330dd0bSAdrian Chadd ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg) 997330dd0bSAdrian Chadd { 1007330dd0bSAdrian Chadd uint32_t t; 1017330dd0bSAdrian Chadd 1027330dd0bSAdrian Chadd if (!cfg) 1037330dd0bSAdrian Chadd return (0); 1047330dd0bSAdrian Chadd 1057330dd0bSAdrian Chadd t = 0; 1067330dd0bSAdrian Chadd switch (cfg->mode) { 1077330dd0bSAdrian Chadd case AR8327_PAD_NC: 1087330dd0bSAdrian Chadd break; 1097330dd0bSAdrian Chadd 1107330dd0bSAdrian Chadd case AR8327_PAD_MAC2MAC_MII: 1117330dd0bSAdrian Chadd t = AR8327_PAD_MAC_MII_EN; 1127330dd0bSAdrian Chadd if (cfg->rxclk_sel) 1137330dd0bSAdrian Chadd t |= AR8327_PAD_MAC_MII_RXCLK_SEL; 1147330dd0bSAdrian Chadd if (cfg->txclk_sel) 1157330dd0bSAdrian Chadd t |= AR8327_PAD_MAC_MII_TXCLK_SEL; 1167330dd0bSAdrian Chadd break; 1177330dd0bSAdrian Chadd 1187330dd0bSAdrian Chadd case AR8327_PAD_MAC2MAC_GMII: 1197330dd0bSAdrian Chadd t = AR8327_PAD_MAC_GMII_EN; 1207330dd0bSAdrian Chadd if (cfg->rxclk_sel) 1217330dd0bSAdrian Chadd t |= AR8327_PAD_MAC_GMII_RXCLK_SEL; 1227330dd0bSAdrian Chadd if (cfg->txclk_sel) 1237330dd0bSAdrian Chadd t |= AR8327_PAD_MAC_GMII_TXCLK_SEL; 1247330dd0bSAdrian Chadd break; 1257330dd0bSAdrian Chadd 1267330dd0bSAdrian Chadd case AR8327_PAD_MAC_SGMII: 1277330dd0bSAdrian Chadd t = AR8327_PAD_SGMII_EN; 1287330dd0bSAdrian Chadd 1297330dd0bSAdrian Chadd /* 1309ab21e32SAdrian Chadd * WAR for the Qualcomm Atheros AP136 board. 1317330dd0bSAdrian Chadd * It seems that RGMII TX/RX delay settings needs to be 1327330dd0bSAdrian Chadd * applied for SGMII mode as well, The ethernet is not 1337330dd0bSAdrian Chadd * reliable without this. 1347330dd0bSAdrian Chadd */ 1357330dd0bSAdrian Chadd t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; 1367330dd0bSAdrian Chadd t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; 1377330dd0bSAdrian Chadd if (cfg->rxclk_delay_en) 1387330dd0bSAdrian Chadd t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; 1397330dd0bSAdrian Chadd if (cfg->txclk_delay_en) 1407330dd0bSAdrian Chadd t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; 1417330dd0bSAdrian Chadd 1427330dd0bSAdrian Chadd if (cfg->sgmii_delay_en) 1437330dd0bSAdrian Chadd t |= AR8327_PAD_SGMII_DELAY_EN; 1447330dd0bSAdrian Chadd 1457330dd0bSAdrian Chadd break; 1467330dd0bSAdrian Chadd 1477330dd0bSAdrian Chadd case AR8327_PAD_MAC2PHY_MII: 1487330dd0bSAdrian Chadd t = AR8327_PAD_PHY_MII_EN; 1497330dd0bSAdrian Chadd if (cfg->rxclk_sel) 1507330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_MII_RXCLK_SEL; 1517330dd0bSAdrian Chadd if (cfg->txclk_sel) 1527330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_MII_TXCLK_SEL; 1537330dd0bSAdrian Chadd break; 1547330dd0bSAdrian Chadd 1557330dd0bSAdrian Chadd case AR8327_PAD_MAC2PHY_GMII: 1567330dd0bSAdrian Chadd t = AR8327_PAD_PHY_GMII_EN; 1577330dd0bSAdrian Chadd if (cfg->pipe_rxclk_sel) 1587330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL; 1597330dd0bSAdrian Chadd if (cfg->rxclk_sel) 1607330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_GMII_RXCLK_SEL; 1617330dd0bSAdrian Chadd if (cfg->txclk_sel) 1627330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_GMII_TXCLK_SEL; 1637330dd0bSAdrian Chadd break; 1647330dd0bSAdrian Chadd 1657330dd0bSAdrian Chadd case AR8327_PAD_MAC_RGMII: 1667330dd0bSAdrian Chadd t = AR8327_PAD_RGMII_EN; 1677330dd0bSAdrian Chadd t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; 1687330dd0bSAdrian Chadd t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; 1697330dd0bSAdrian Chadd if (cfg->rxclk_delay_en) 1707330dd0bSAdrian Chadd t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; 1717330dd0bSAdrian Chadd if (cfg->txclk_delay_en) 1727330dd0bSAdrian Chadd t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; 1737330dd0bSAdrian Chadd break; 1747330dd0bSAdrian Chadd 1757330dd0bSAdrian Chadd case AR8327_PAD_PHY_GMII: 1767330dd0bSAdrian Chadd t = AR8327_PAD_PHYX_GMII_EN; 1777330dd0bSAdrian Chadd break; 1787330dd0bSAdrian Chadd 1797330dd0bSAdrian Chadd case AR8327_PAD_PHY_RGMII: 1807330dd0bSAdrian Chadd t = AR8327_PAD_PHYX_RGMII_EN; 1817330dd0bSAdrian Chadd break; 1827330dd0bSAdrian Chadd 1837330dd0bSAdrian Chadd case AR8327_PAD_PHY_MII: 1847330dd0bSAdrian Chadd t = AR8327_PAD_PHYX_MII_EN; 1857330dd0bSAdrian Chadd break; 1867330dd0bSAdrian Chadd } 1877330dd0bSAdrian Chadd 1887330dd0bSAdrian Chadd return (t); 1897330dd0bSAdrian Chadd } 1907330dd0bSAdrian Chadd 1917330dd0bSAdrian Chadd /* 1927330dd0bSAdrian Chadd * Map the hard-coded port config from the switch setup to 1937330dd0bSAdrian Chadd * the chipset port config (status, duplex, flow, etc.) 1947330dd0bSAdrian Chadd */ 1957330dd0bSAdrian Chadd static uint32_t 1967330dd0bSAdrian Chadd ar8327_get_port_init_status(struct ar8327_port_cfg *cfg) 1977330dd0bSAdrian Chadd { 1987330dd0bSAdrian Chadd uint32_t t; 1997330dd0bSAdrian Chadd 2007330dd0bSAdrian Chadd if (!cfg->force_link) 2017330dd0bSAdrian Chadd return (AR8X16_PORT_STS_LINK_AUTO); 2027330dd0bSAdrian Chadd 2037330dd0bSAdrian Chadd t = AR8X16_PORT_STS_TXMAC | AR8X16_PORT_STS_RXMAC; 2047330dd0bSAdrian Chadd t |= cfg->duplex ? AR8X16_PORT_STS_DUPLEX : 0; 2057330dd0bSAdrian Chadd t |= cfg->rxpause ? AR8X16_PORT_STS_RXFLOW : 0; 2067330dd0bSAdrian Chadd t |= cfg->txpause ? AR8X16_PORT_STS_TXFLOW : 0; 2077330dd0bSAdrian Chadd 2087330dd0bSAdrian Chadd switch (cfg->speed) { 2097330dd0bSAdrian Chadd case AR8327_PORT_SPEED_10: 2107330dd0bSAdrian Chadd t |= AR8X16_PORT_STS_SPEED_10; 2117330dd0bSAdrian Chadd break; 2127330dd0bSAdrian Chadd case AR8327_PORT_SPEED_100: 2137330dd0bSAdrian Chadd t |= AR8X16_PORT_STS_SPEED_100; 2147330dd0bSAdrian Chadd break; 2157330dd0bSAdrian Chadd case AR8327_PORT_SPEED_1000: 2167330dd0bSAdrian Chadd t |= AR8X16_PORT_STS_SPEED_1000; 2177330dd0bSAdrian Chadd break; 2187330dd0bSAdrian Chadd } 2197330dd0bSAdrian Chadd 2207330dd0bSAdrian Chadd return (t); 2217330dd0bSAdrian Chadd } 2229ab21e32SAdrian Chadd 2239ab21e32SAdrian Chadd /* 224f9950f9aSAdrian Chadd * Fetch the port data for the given port. 225f9950f9aSAdrian Chadd * 226f9950f9aSAdrian Chadd * This goes and does dirty things with the hints space 227f9950f9aSAdrian Chadd * to determine what the configuration parameters should be. 228f9950f9aSAdrian Chadd * 229f9950f9aSAdrian Chadd * Returns 1 if the structure was successfully parsed and 230f9950f9aSAdrian Chadd * the contents are valid; 0 otherwise. 231f9950f9aSAdrian Chadd */ 232f9950f9aSAdrian Chadd static int 233f9950f9aSAdrian Chadd ar8327_fetch_pdata_port(struct arswitch_softc *sc, 234f9950f9aSAdrian Chadd struct ar8327_port_cfg *pcfg, 235f9950f9aSAdrian Chadd int port) 236f9950f9aSAdrian Chadd { 237f9950f9aSAdrian Chadd int val; 238f9950f9aSAdrian Chadd char sbuf[128]; 239f9950f9aSAdrian Chadd 240f9950f9aSAdrian Chadd /* Check if force_link exists */ 241f9950f9aSAdrian Chadd val = 0; 242f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.force_link", port); 243f9950f9aSAdrian Chadd (void) resource_int_value(device_get_name(sc->sc_dev), 244f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 245f9950f9aSAdrian Chadd sbuf, &val); 246f9950f9aSAdrian Chadd if (val != 1) 247f9950f9aSAdrian Chadd return (0); 248f9950f9aSAdrian Chadd pcfg->force_link = 1; 249f9950f9aSAdrian Chadd 250f9950f9aSAdrian Chadd /* force_link is set; let's parse the rest of the fields */ 251f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.speed", port); 252f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 253f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 254f9950f9aSAdrian Chadd sbuf, &val) == 0) { 255f9950f9aSAdrian Chadd switch (val) { 256f9950f9aSAdrian Chadd case 10: 257f9950f9aSAdrian Chadd pcfg->speed = AR8327_PORT_SPEED_10; 258f9950f9aSAdrian Chadd break; 259f9950f9aSAdrian Chadd case 100: 260f9950f9aSAdrian Chadd pcfg->speed = AR8327_PORT_SPEED_100; 261f9950f9aSAdrian Chadd break; 262f9950f9aSAdrian Chadd case 1000: 263f9950f9aSAdrian Chadd pcfg->speed = AR8327_PORT_SPEED_1000; 264f9950f9aSAdrian Chadd break; 265f9950f9aSAdrian Chadd default: 266f9950f9aSAdrian Chadd device_printf(sc->sc_dev, 267f9950f9aSAdrian Chadd "%s: invalid port %d duplex value (%d)\n", 268f9950f9aSAdrian Chadd __func__, 269f9950f9aSAdrian Chadd port, 270f9950f9aSAdrian Chadd val); 271f9950f9aSAdrian Chadd return (0); 272f9950f9aSAdrian Chadd } 273f9950f9aSAdrian Chadd } 274f9950f9aSAdrian Chadd 275f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.duplex", port); 276f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 277f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 278f9950f9aSAdrian Chadd sbuf, &val) == 0) 279f9950f9aSAdrian Chadd pcfg->duplex = val; 280f9950f9aSAdrian Chadd 281f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.txpause", port); 282f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 283f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 284f9950f9aSAdrian Chadd sbuf, &val) == 0) 285f9950f9aSAdrian Chadd pcfg->txpause = val; 286f9950f9aSAdrian Chadd 287f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.rxpause", port); 288f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 289f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 290f9950f9aSAdrian Chadd sbuf, &val) == 0) 291f9950f9aSAdrian Chadd pcfg->rxpause = val; 292f9950f9aSAdrian Chadd 293f9950f9aSAdrian Chadd #if 0 294f9950f9aSAdrian Chadd device_printf(sc->sc_dev, 295f9950f9aSAdrian Chadd "%s: port %d: speed=%d, duplex=%d, txpause=%d, rxpause=%d\n", 296f9950f9aSAdrian Chadd __func__, 297f9950f9aSAdrian Chadd port, 298f9950f9aSAdrian Chadd pcfg->speed, 299f9950f9aSAdrian Chadd pcfg->duplex, 300f9950f9aSAdrian Chadd pcfg->txpause, 301f9950f9aSAdrian Chadd pcfg->rxpause); 302f9950f9aSAdrian Chadd #endif 303f9950f9aSAdrian Chadd 304f9950f9aSAdrian Chadd return (1); 305f9950f9aSAdrian Chadd } 306f9950f9aSAdrian Chadd 307f9950f9aSAdrian Chadd /* 308f9950f9aSAdrian Chadd * Parse the pad configuration from the boot hints. 309f9950f9aSAdrian Chadd * 310f9950f9aSAdrian Chadd * The (mostly optional) fields are: 311f9950f9aSAdrian Chadd * 312f9950f9aSAdrian Chadd * uint32_t mode; 313f9950f9aSAdrian Chadd * uint32_t rxclk_sel; 314f9950f9aSAdrian Chadd * uint32_t txclk_sel; 315f9950f9aSAdrian Chadd * uint32_t txclk_delay_sel; 316f9950f9aSAdrian Chadd * uint32_t rxclk_delay_sel; 317f9950f9aSAdrian Chadd * uint32_t txclk_delay_en; 318f9950f9aSAdrian Chadd * uint32_t rxclk_delay_en; 319f9950f9aSAdrian Chadd * uint32_t sgmii_delay_en; 320f9950f9aSAdrian Chadd * uint32_t pipe_rxclk_sel; 321f9950f9aSAdrian Chadd * 322f9950f9aSAdrian Chadd * If mode isn't in the hints, 0 is returned. 323f9950f9aSAdrian Chadd * Else the structure is fleshed out and 1 is returned. 324f9950f9aSAdrian Chadd */ 325f9950f9aSAdrian Chadd static int 326f9950f9aSAdrian Chadd ar8327_fetch_pdata_pad(struct arswitch_softc *sc, 327f9950f9aSAdrian Chadd struct ar8327_pad_cfg *pc, 328f9950f9aSAdrian Chadd int pad) 329f9950f9aSAdrian Chadd { 330f9950f9aSAdrian Chadd int val; 331f9950f9aSAdrian Chadd char sbuf[128]; 332f9950f9aSAdrian Chadd 333f9950f9aSAdrian Chadd /* Check if mode exists */ 334f9950f9aSAdrian Chadd val = 0; 335f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.mode", pad); 336f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 337f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 338f9950f9aSAdrian Chadd sbuf, &val) != 0) 339f9950f9aSAdrian Chadd return (0); 340f9950f9aSAdrian Chadd 341f9950f9aSAdrian Chadd /* assume that 'mode' exists and was found */ 342f9950f9aSAdrian Chadd pc->mode = val; 343f9950f9aSAdrian Chadd 344f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.rxclk_sel", pad); 345f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 346f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 347f9950f9aSAdrian Chadd sbuf, &val) == 0) 348f9950f9aSAdrian Chadd pc->rxclk_sel = val; 349f9950f9aSAdrian Chadd 350f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.txclk_sel", pad); 351f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 352f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 353f9950f9aSAdrian Chadd sbuf, &val) == 0) 354f9950f9aSAdrian Chadd pc->txclk_sel = val; 355f9950f9aSAdrian Chadd 356f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.txclk_delay_sel", pad); 357f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 358f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 359f9950f9aSAdrian Chadd sbuf, &val) == 0) 360f9950f9aSAdrian Chadd pc->txclk_delay_sel = val; 361f9950f9aSAdrian Chadd 362f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.rxclk_delay_sel", pad); 363f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 364f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 365f9950f9aSAdrian Chadd sbuf, &val) == 0) 366f9950f9aSAdrian Chadd pc->rxclk_delay_sel = val; 367f9950f9aSAdrian Chadd 368f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.txclk_delay_en", pad); 369f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 370f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 371f9950f9aSAdrian Chadd sbuf, &val) == 0) 372f9950f9aSAdrian Chadd pc->txclk_delay_en = val; 373f9950f9aSAdrian Chadd 374f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.rxclk_delay_en", pad); 375f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 376f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 377f9950f9aSAdrian Chadd sbuf, &val) == 0) 378f9950f9aSAdrian Chadd pc->rxclk_delay_en = val; 379f9950f9aSAdrian Chadd 380f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.sgmii_delay_en", pad); 381f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 382f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 383f9950f9aSAdrian Chadd sbuf, &val) == 0) 384f9950f9aSAdrian Chadd pc->sgmii_delay_en = val; 385f9950f9aSAdrian Chadd 386f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.pipe_rxclk_sel", pad); 387f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 388f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 389f9950f9aSAdrian Chadd sbuf, &val) == 0) 390f9950f9aSAdrian Chadd pc->pipe_rxclk_sel = val; 391f9950f9aSAdrian Chadd 392*db37238fSAdrian Chadd if (bootverbose) { 393f9950f9aSAdrian Chadd device_printf(sc->sc_dev, 394f9950f9aSAdrian Chadd "%s: pad %d: mode=%d, rxclk_sel=%d, txclk_sel=%d, " 395f9950f9aSAdrian Chadd "txclk_delay_sel=%d, rxclk_delay_sel=%d, txclk_delay_en=%d, " 396f9950f9aSAdrian Chadd "rxclk_enable_en=%d, sgmii_delay_en=%d, pipe_rxclk_sel=%d\n", 397f9950f9aSAdrian Chadd __func__, 398f9950f9aSAdrian Chadd pad, 399f9950f9aSAdrian Chadd pc->mode, 400f9950f9aSAdrian Chadd pc->rxclk_sel, 401f9950f9aSAdrian Chadd pc->txclk_sel, 402f9950f9aSAdrian Chadd pc->txclk_delay_sel, 403f9950f9aSAdrian Chadd pc->rxclk_delay_sel, 404f9950f9aSAdrian Chadd pc->txclk_delay_en, 405f9950f9aSAdrian Chadd pc->rxclk_delay_en, 406f9950f9aSAdrian Chadd pc->sgmii_delay_en, 407f9950f9aSAdrian Chadd pc->pipe_rxclk_sel); 408*db37238fSAdrian Chadd } 409f9950f9aSAdrian Chadd 410f9950f9aSAdrian Chadd return (1); 411f9950f9aSAdrian Chadd } 412f9950f9aSAdrian Chadd 413f9950f9aSAdrian Chadd /* 414810bdeddSAdrian Chadd * Fetch the SGMII configuration block from the boot hints. 415810bdeddSAdrian Chadd */ 416810bdeddSAdrian Chadd static int 417810bdeddSAdrian Chadd ar8327_fetch_pdata_sgmii(struct arswitch_softc *sc, 418810bdeddSAdrian Chadd struct ar8327_sgmii_cfg *scfg) 419810bdeddSAdrian Chadd { 420810bdeddSAdrian Chadd int val; 421810bdeddSAdrian Chadd 422810bdeddSAdrian Chadd /* sgmii_ctrl */ 423810bdeddSAdrian Chadd val = 0; 424810bdeddSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 425810bdeddSAdrian Chadd device_get_unit(sc->sc_dev), 426810bdeddSAdrian Chadd "sgmii.ctrl", &val) != 0) 427810bdeddSAdrian Chadd return (0); 428810bdeddSAdrian Chadd scfg->sgmii_ctrl = val; 429810bdeddSAdrian Chadd 430810bdeddSAdrian Chadd /* serdes_aen */ 431810bdeddSAdrian Chadd val = 0; 432810bdeddSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 433810bdeddSAdrian Chadd device_get_unit(sc->sc_dev), 434810bdeddSAdrian Chadd "sgmii.serdes_aen", &val) != 0) 435810bdeddSAdrian Chadd return (0); 436810bdeddSAdrian Chadd scfg->serdes_aen = val; 437810bdeddSAdrian Chadd 438810bdeddSAdrian Chadd return (1); 439810bdeddSAdrian Chadd } 440810bdeddSAdrian Chadd 441810bdeddSAdrian Chadd /* 442b67ba111SAdrian Chadd * Fetch the LED configuration from the boot hints. 443b67ba111SAdrian Chadd */ 444b67ba111SAdrian Chadd static int 445b67ba111SAdrian Chadd ar8327_fetch_pdata_led(struct arswitch_softc *sc, 446b67ba111SAdrian Chadd struct ar8327_led_cfg *lcfg) 447b67ba111SAdrian Chadd { 448b67ba111SAdrian Chadd int val; 449b67ba111SAdrian Chadd 450b67ba111SAdrian Chadd val = 0; 451b67ba111SAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 452b67ba111SAdrian Chadd device_get_unit(sc->sc_dev), 453b67ba111SAdrian Chadd "led.ctrl0", &val) != 0) 454b67ba111SAdrian Chadd return (0); 455b67ba111SAdrian Chadd lcfg->led_ctrl0 = val; 456b67ba111SAdrian Chadd 457b67ba111SAdrian Chadd val = 0; 458b67ba111SAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 459b67ba111SAdrian Chadd device_get_unit(sc->sc_dev), 460b67ba111SAdrian Chadd "led.ctrl1", &val) != 0) 461b67ba111SAdrian Chadd return (0); 462b67ba111SAdrian Chadd lcfg->led_ctrl1 = val; 463b67ba111SAdrian Chadd 464b67ba111SAdrian Chadd val = 0; 465b67ba111SAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 466b67ba111SAdrian Chadd device_get_unit(sc->sc_dev), 467b67ba111SAdrian Chadd "led.ctrl2", &val) != 0) 468b67ba111SAdrian Chadd return (0); 469b67ba111SAdrian Chadd lcfg->led_ctrl2 = val; 470b67ba111SAdrian Chadd 471b67ba111SAdrian Chadd val = 0; 472b67ba111SAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 473b67ba111SAdrian Chadd device_get_unit(sc->sc_dev), 474b67ba111SAdrian Chadd "led.ctrl3", &val) != 0) 475b67ba111SAdrian Chadd return (0); 476b67ba111SAdrian Chadd lcfg->led_ctrl3 = val; 477b67ba111SAdrian Chadd 478b67ba111SAdrian Chadd val = 0; 479b67ba111SAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 480b67ba111SAdrian Chadd device_get_unit(sc->sc_dev), 481b67ba111SAdrian Chadd "led.open_drain", &val) != 0) 482b67ba111SAdrian Chadd return (0); 483b67ba111SAdrian Chadd lcfg->open_drain = val; 484b67ba111SAdrian Chadd 485b67ba111SAdrian Chadd return (1); 486b67ba111SAdrian Chadd } 487b67ba111SAdrian Chadd 488b67ba111SAdrian Chadd /* 4899ab21e32SAdrian Chadd * Initialise the ar8327 specific hardware features from 4909ab21e32SAdrian Chadd * the hints provided in the boot environment. 4919ab21e32SAdrian Chadd */ 4929ab21e32SAdrian Chadd static int 4939ab21e32SAdrian Chadd ar8327_init_pdata(struct arswitch_softc *sc) 4949ab21e32SAdrian Chadd { 4959ab21e32SAdrian Chadd struct ar8327_pad_cfg pc; 4969ab21e32SAdrian Chadd struct ar8327_port_cfg port_cfg; 497810bdeddSAdrian Chadd struct ar8327_sgmii_cfg scfg; 498b67ba111SAdrian Chadd struct ar8327_led_cfg lcfg; 499810bdeddSAdrian Chadd uint32_t t, new_pos, pos; 5009ab21e32SAdrian Chadd 501f9950f9aSAdrian Chadd /* Port 0 */ 5029ab21e32SAdrian Chadd bzero(&port_cfg, sizeof(port_cfg)); 503f9950f9aSAdrian Chadd sc->ar8327.port0_status = 0; 504f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_port(sc, &port_cfg, 0)) 5059ab21e32SAdrian Chadd sc->ar8327.port0_status = ar8327_get_port_init_status(&port_cfg); 5069ab21e32SAdrian Chadd 507f9950f9aSAdrian Chadd /* Port 6 */ 5089ab21e32SAdrian Chadd bzero(&port_cfg, sizeof(port_cfg)); 509f9950f9aSAdrian Chadd sc->ar8327.port6_status = 0; 510f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_port(sc, &port_cfg, 6)) 5119ab21e32SAdrian Chadd sc->ar8327.port6_status = ar8327_get_port_init_status(&port_cfg); 5129ab21e32SAdrian Chadd 5139ab21e32SAdrian Chadd /* Pad 0 */ 5149ab21e32SAdrian Chadd bzero(&pc, sizeof(pc)); 515f9950f9aSAdrian Chadd t = 0; 516f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_pad(sc, &pc, 0)) 5179ab21e32SAdrian Chadd t = ar8327_get_pad_cfg(&pc); 5189ab21e32SAdrian Chadd #if 0 5199ab21e32SAdrian Chadd if (AR8X16_IS_SWITCH(sc, AR8337)) 5209ab21e32SAdrian Chadd t |= AR8337_PAD_MAC06_EXCHANGE_EN; 5217330dd0bSAdrian Chadd #endif 5229ab21e32SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PAD0_MODE, t); 5239ab21e32SAdrian Chadd 5249ab21e32SAdrian Chadd /* Pad 5 */ 5259ab21e32SAdrian Chadd bzero(&pc, sizeof(pc)); 526f9950f9aSAdrian Chadd t = 0; 527f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_pad(sc, &pc, 5)) 5289ab21e32SAdrian Chadd t = ar8327_get_pad_cfg(&pc); 5299ab21e32SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PAD5_MODE, t); 5309ab21e32SAdrian Chadd 5319ab21e32SAdrian Chadd /* Pad 6 */ 5329ab21e32SAdrian Chadd bzero(&pc, sizeof(pc)); 533f9950f9aSAdrian Chadd t = 0; 534f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_pad(sc, &pc, 6)) 5359ab21e32SAdrian Chadd t = ar8327_get_pad_cfg(&pc); 5369ab21e32SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PAD6_MODE, t); 5379ab21e32SAdrian Chadd 538810bdeddSAdrian Chadd pos = arswitch_readreg(sc->sc_dev, AR8327_REG_POWER_ON_STRIP); 539810bdeddSAdrian Chadd new_pos = pos; 540810bdeddSAdrian Chadd 5419ab21e32SAdrian Chadd /* XXX LED config */ 542b67ba111SAdrian Chadd bzero(&lcfg, sizeof(lcfg)); 543b67ba111SAdrian Chadd if (ar8327_fetch_pdata_led(sc, &lcfg)) { 544b67ba111SAdrian Chadd if (lcfg.open_drain) 545b67ba111SAdrian Chadd new_pos |= AR8327_POWER_ON_STRIP_LED_OPEN_EN; 546b67ba111SAdrian Chadd else 547b67ba111SAdrian Chadd new_pos &= ~AR8327_POWER_ON_STRIP_LED_OPEN_EN; 548b67ba111SAdrian Chadd 549b67ba111SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_LED_CTRL0, 550b67ba111SAdrian Chadd lcfg.led_ctrl0); 551b67ba111SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_LED_CTRL1, 552b67ba111SAdrian Chadd lcfg.led_ctrl1); 553b67ba111SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_LED_CTRL2, 554b67ba111SAdrian Chadd lcfg.led_ctrl2); 555b67ba111SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_LED_CTRL3, 556b67ba111SAdrian Chadd lcfg.led_ctrl3); 557b67ba111SAdrian Chadd 558b67ba111SAdrian Chadd if (new_pos != pos) 559b67ba111SAdrian Chadd new_pos |= AR8327_POWER_ON_STRIP_POWER_ON_SEL; 560b67ba111SAdrian Chadd } 5619ab21e32SAdrian Chadd 562810bdeddSAdrian Chadd /* SGMII config */ 563810bdeddSAdrian Chadd bzero(&scfg, sizeof(scfg)); 564810bdeddSAdrian Chadd if (ar8327_fetch_pdata_sgmii(sc, &scfg)) { 565810bdeddSAdrian Chadd t = scfg.sgmii_ctrl; 566810bdeddSAdrian Chadd if (sc->chip_rev == 1) 567810bdeddSAdrian Chadd t |= AR8327_SGMII_CTRL_EN_PLL | 568810bdeddSAdrian Chadd AR8327_SGMII_CTRL_EN_RX | 569810bdeddSAdrian Chadd AR8327_SGMII_CTRL_EN_TX; 570810bdeddSAdrian Chadd else 571810bdeddSAdrian Chadd t &= ~(AR8327_SGMII_CTRL_EN_PLL | 572810bdeddSAdrian Chadd AR8327_SGMII_CTRL_EN_RX | 573810bdeddSAdrian Chadd AR8327_SGMII_CTRL_EN_TX); 574810bdeddSAdrian Chadd 575810bdeddSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_SGMII_CTRL, t); 576810bdeddSAdrian Chadd 577810bdeddSAdrian Chadd if (scfg.serdes_aen) 578810bdeddSAdrian Chadd new_pos &= ~AR8327_POWER_ON_STRIP_SERDES_AEN; 579810bdeddSAdrian Chadd else 580810bdeddSAdrian Chadd new_pos |= AR8327_POWER_ON_STRIP_SERDES_AEN; 581810bdeddSAdrian Chadd } 582810bdeddSAdrian Chadd 583810bdeddSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_POWER_ON_STRIP, new_pos); 5849ab21e32SAdrian Chadd 5859ab21e32SAdrian Chadd return (0); 5869ab21e32SAdrian Chadd } 5877330dd0bSAdrian Chadd 5887330dd0bSAdrian Chadd static int 5897330dd0bSAdrian Chadd ar8327_hw_setup(struct arswitch_softc *sc) 5907330dd0bSAdrian Chadd { 5917330dd0bSAdrian Chadd int i; 5927330dd0bSAdrian Chadd int err; 5937330dd0bSAdrian Chadd 5947330dd0bSAdrian Chadd /* pdata fetch and setup */ 5957330dd0bSAdrian Chadd err = ar8327_init_pdata(sc); 5967330dd0bSAdrian Chadd if (err != 0) 5977330dd0bSAdrian Chadd return (err); 5987330dd0bSAdrian Chadd 5997330dd0bSAdrian Chadd /* XXX init leds */ 6007330dd0bSAdrian Chadd 6017330dd0bSAdrian Chadd for (i = 0; i < AR8327_NUM_PHYS; i++) { 6027330dd0bSAdrian Chadd /* phy fixup */ 6037330dd0bSAdrian Chadd ar8327_phy_fixup(sc, i); 6047330dd0bSAdrian Chadd 6057330dd0bSAdrian Chadd /* start PHY autonegotiation? */ 6067330dd0bSAdrian Chadd /* XXX is this done as part of the normal PHY setup? */ 6077330dd0bSAdrian Chadd 6087330dd0bSAdrian Chadd }; 6097330dd0bSAdrian Chadd 6107330dd0bSAdrian Chadd /* Let things settle */ 6117330dd0bSAdrian Chadd DELAY(1000); 6127330dd0bSAdrian Chadd 6137330dd0bSAdrian Chadd return (0); 6147330dd0bSAdrian Chadd } 6157330dd0bSAdrian Chadd 6167330dd0bSAdrian Chadd /* 6177330dd0bSAdrian Chadd * Initialise other global values, for the AR8327. 6187330dd0bSAdrian Chadd */ 6197330dd0bSAdrian Chadd static int 6207330dd0bSAdrian Chadd ar8327_hw_global_setup(struct arswitch_softc *sc) 6217330dd0bSAdrian Chadd { 6227330dd0bSAdrian Chadd uint32_t t; 6237330dd0bSAdrian Chadd 6247330dd0bSAdrian Chadd /* enable CPU port and disable mirror port */ 6257330dd0bSAdrian Chadd t = AR8327_FWD_CTRL0_CPU_PORT_EN | 6267330dd0bSAdrian Chadd AR8327_FWD_CTRL0_MIRROR_PORT; 6277330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_FWD_CTRL0, t); 6287330dd0bSAdrian Chadd 6297330dd0bSAdrian Chadd /* forward multicast and broadcast frames to CPU */ 6307330dd0bSAdrian Chadd t = (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_UC_FLOOD_S) | 6317330dd0bSAdrian Chadd (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_MC_FLOOD_S) | 6327330dd0bSAdrian Chadd (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_BC_FLOOD_S); 6337330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_FWD_CTRL1, t); 6347330dd0bSAdrian Chadd 6357330dd0bSAdrian Chadd /* enable jumbo frames */ 6367330dd0bSAdrian Chadd /* XXX need to macro-shift the value! */ 6377330dd0bSAdrian Chadd arswitch_modifyreg(sc->sc_dev, AR8327_REG_MAX_FRAME_SIZE, 6387330dd0bSAdrian Chadd AR8327_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2); 6397330dd0bSAdrian Chadd 6407330dd0bSAdrian Chadd /* Enable MIB counters */ 6417330dd0bSAdrian Chadd arswitch_modifyreg(sc->sc_dev, AR8327_REG_MODULE_EN, 6427330dd0bSAdrian Chadd AR8327_MODULE_EN_MIB, AR8327_MODULE_EN_MIB); 6437330dd0bSAdrian Chadd 644*db37238fSAdrian Chadd /* Disable EEE on all ports due to stability issues */ 645*db37238fSAdrian Chadd t = arswitch_readreg(sc->sc_dev, AR8327_REG_EEE_CTRL); 646*db37238fSAdrian Chadd t |= AR8327_EEE_CTRL_DISABLE_PHY(0) | 647*db37238fSAdrian Chadd AR8327_EEE_CTRL_DISABLE_PHY(1) | 648*db37238fSAdrian Chadd AR8327_EEE_CTRL_DISABLE_PHY(2) | 649*db37238fSAdrian Chadd AR8327_EEE_CTRL_DISABLE_PHY(3) | 650*db37238fSAdrian Chadd AR8327_EEE_CTRL_DISABLE_PHY(4); 651*db37238fSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_EEE_CTRL, t); 652*db37238fSAdrian Chadd 6534ff2f60dSAdrian Chadd /* Set the right number of ports */ 6544ff2f60dSAdrian Chadd sc->info.es_nports = 6; 6554ff2f60dSAdrian Chadd 6567330dd0bSAdrian Chadd return (0); 6577330dd0bSAdrian Chadd } 6587330dd0bSAdrian Chadd 6597330dd0bSAdrian Chadd /* 6607330dd0bSAdrian Chadd * Port setup. 6617330dd0bSAdrian Chadd */ 6627330dd0bSAdrian Chadd static void 6637330dd0bSAdrian Chadd ar8327_port_init(struct arswitch_softc *sc, int port) 6647330dd0bSAdrian Chadd { 6657330dd0bSAdrian Chadd uint32_t t; 6667330dd0bSAdrian Chadd 6679ab21e32SAdrian Chadd if (port == AR8X16_PORT_CPU) 6689ab21e32SAdrian Chadd t = sc->ar8327.port0_status; 6697330dd0bSAdrian Chadd else if (port == 6) 6709ab21e32SAdrian Chadd t = sc->ar8327.port6_status; 6717330dd0bSAdrian Chadd else 6727330dd0bSAdrian Chadd t = AR8X16_PORT_STS_LINK_AUTO; 6737330dd0bSAdrian Chadd 6747330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_STATUS(port), t); 6757330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_HEADER(port), 0); 6767330dd0bSAdrian Chadd 6770d2041a0SAdrian Chadd /* 6780d2041a0SAdrian Chadd * Default to 1 port group. 6790d2041a0SAdrian Chadd */ 6807330dd0bSAdrian Chadd t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S; 6817330dd0bSAdrian Chadd t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S; 6827330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN0(port), t); 6837330dd0bSAdrian Chadd 6847330dd0bSAdrian Chadd t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S; 6857330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN1(port), t); 6867330dd0bSAdrian Chadd 68703b5d827SAdrian Chadd /* 68803b5d827SAdrian Chadd * This doesn't configure any ports which this port can "see". 68903b5d827SAdrian Chadd * bits 0-6 control which ports a frame coming into this port 69003b5d827SAdrian Chadd * can be sent out to. 69103b5d827SAdrian Chadd * 69203b5d827SAdrian Chadd * So by doing this, we're making it impossible to send frames out 69303b5d827SAdrian Chadd * to that port. 69403b5d827SAdrian Chadd */ 6957330dd0bSAdrian Chadd t = AR8327_PORT_LOOKUP_LEARN; 6967330dd0bSAdrian Chadd t |= AR8X16_PORT_CTRL_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; 69703b5d827SAdrian Chadd 69803b5d827SAdrian Chadd /* So this allows traffic to any port except ourselves */ 6997190a55cSAdrian Chadd t |= (0x7f & ~(1 << port)); 7007330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(port), t); 7017330dd0bSAdrian Chadd } 7027330dd0bSAdrian Chadd 7037330dd0bSAdrian Chadd static int 7047330dd0bSAdrian Chadd ar8327_port_vlan_setup(struct arswitch_softc *sc, etherswitch_port_t *p) 7057330dd0bSAdrian Chadd { 7067330dd0bSAdrian Chadd 7077330dd0bSAdrian Chadd /* XXX stub for now */ 7087330dd0bSAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 7097330dd0bSAdrian Chadd return (0); 7107330dd0bSAdrian Chadd } 7117330dd0bSAdrian Chadd 7127330dd0bSAdrian Chadd static int 7137330dd0bSAdrian Chadd ar8327_port_vlan_get(struct arswitch_softc *sc, etherswitch_port_t *p) 7147330dd0bSAdrian Chadd { 7157330dd0bSAdrian Chadd 7167330dd0bSAdrian Chadd /* XXX stub for now */ 7177330dd0bSAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 7187330dd0bSAdrian Chadd return (0); 7197330dd0bSAdrian Chadd } 7207330dd0bSAdrian Chadd 7217330dd0bSAdrian Chadd static void 7227330dd0bSAdrian Chadd ar8327_reset_vlans(struct arswitch_softc *sc) 7237330dd0bSAdrian Chadd { 7247330dd0bSAdrian Chadd int i; 7257330dd0bSAdrian Chadd uint32_t mode, t; 7267330dd0bSAdrian Chadd 7277330dd0bSAdrian Chadd /* 72803b5d827SAdrian Chadd * Disable mirroring. 72903b5d827SAdrian Chadd */ 73003b5d827SAdrian Chadd arswitch_modifyreg(sc->sc_dev, AR8327_REG_FWD_CTRL0, 73103b5d827SAdrian Chadd AR8327_FWD_CTRL0_MIRROR_PORT, 73203b5d827SAdrian Chadd (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S)); 73303b5d827SAdrian Chadd 73403b5d827SAdrian Chadd /* 7357330dd0bSAdrian Chadd * For now, let's default to one portgroup, just so traffic 7367330dd0bSAdrian Chadd * flows. All ports can see other ports. 7377330dd0bSAdrian Chadd */ 7387330dd0bSAdrian Chadd for (i = 0; i < AR8327_NUM_PORTS; i++) { 739dd846bddSAdrian Chadd /* set pvid = 1; there's only one vlangroup */ 740dd846bddSAdrian Chadd t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S; 741dd846bddSAdrian Chadd t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S; 7427330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN0(i), t); 7437330dd0bSAdrian Chadd 7447330dd0bSAdrian Chadd /* set egress == out_keep */ 7457330dd0bSAdrian Chadd mode = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH; 7467330dd0bSAdrian Chadd 7477330dd0bSAdrian Chadd t = AR8327_PORT_VLAN1_PORT_VLAN_PROP; 7487330dd0bSAdrian Chadd t |= mode << AR8327_PORT_VLAN1_OUT_MODE_S; 7497330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN1(i), t); 7507330dd0bSAdrian Chadd 751dd846bddSAdrian Chadd /* Ports can see other ports */ 7527190a55cSAdrian Chadd t = (0x7f & ~(1 << i)); /* all ports besides us */ 7537330dd0bSAdrian Chadd t |= AR8327_PORT_LOOKUP_LEARN; 7547330dd0bSAdrian Chadd 7557330dd0bSAdrian Chadd /* in_port_only, forward */ 7567330dd0bSAdrian Chadd t |= AR8X16_PORT_VLAN_MODE_PORT_ONLY << AR8327_PORT_LOOKUP_IN_MODE_S; 7577330dd0bSAdrian Chadd t |= AR8X16_PORT_CTRL_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; 7587330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(i), t); 75903b5d827SAdrian Chadd 76003b5d827SAdrian Chadd /* 76103b5d827SAdrian Chadd * Disable port mirroring entirely. 76203b5d827SAdrian Chadd */ 76303b5d827SAdrian Chadd arswitch_modifyreg(sc->sc_dev, 76403b5d827SAdrian Chadd AR8327_REG_PORT_LOOKUP(i), 76503b5d827SAdrian Chadd AR8327_PORT_LOOKUP_ING_MIRROR_EN, 76603b5d827SAdrian Chadd 0); 76703b5d827SAdrian Chadd arswitch_modifyreg(sc->sc_dev, 76803b5d827SAdrian Chadd AR8327_REG_PORT_HOL_CTRL1(i), 76903b5d827SAdrian Chadd AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN, 77003b5d827SAdrian Chadd 0); 7717330dd0bSAdrian Chadd } 7727330dd0bSAdrian Chadd } 7737330dd0bSAdrian Chadd 7747330dd0bSAdrian Chadd static int 7757330dd0bSAdrian Chadd ar8327_vlan_getvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg) 7767330dd0bSAdrian Chadd { 7777330dd0bSAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 7787330dd0bSAdrian Chadd return (0); 7797330dd0bSAdrian Chadd } 7807330dd0bSAdrian Chadd 7817330dd0bSAdrian Chadd static int 7827330dd0bSAdrian Chadd ar8327_vlan_setvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg) 7837330dd0bSAdrian Chadd { 7847330dd0bSAdrian Chadd 7857330dd0bSAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 7867330dd0bSAdrian Chadd return (0); 7877330dd0bSAdrian Chadd } 7887330dd0bSAdrian Chadd 7897330dd0bSAdrian Chadd static int 7907330dd0bSAdrian Chadd ar8327_get_pvid(struct arswitch_softc *sc, int port, int *pvid) 7917330dd0bSAdrian Chadd { 7927330dd0bSAdrian Chadd 7937330dd0bSAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 7947330dd0bSAdrian Chadd return (0); 7957330dd0bSAdrian Chadd } 7967330dd0bSAdrian Chadd 7977330dd0bSAdrian Chadd static int 7987330dd0bSAdrian Chadd ar8327_set_pvid(struct arswitch_softc *sc, int port, int pvid) 7997330dd0bSAdrian Chadd { 8007330dd0bSAdrian Chadd 8017330dd0bSAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 8027330dd0bSAdrian Chadd return (0); 8037330dd0bSAdrian Chadd } 8047330dd0bSAdrian Chadd 8054ff2f60dSAdrian Chadd static int 8064ff2f60dSAdrian Chadd ar8327_atu_flush(struct arswitch_softc *sc) 8074ff2f60dSAdrian Chadd { 8084ff2f60dSAdrian Chadd 8094ff2f60dSAdrian Chadd int ret; 8104ff2f60dSAdrian Chadd 8114ff2f60dSAdrian Chadd ret = arswitch_waitreg(sc->sc_dev, 8124ff2f60dSAdrian Chadd AR8327_REG_ATU_FUNC, 8134ff2f60dSAdrian Chadd AR8327_ATU_FUNC_BUSY, 8144ff2f60dSAdrian Chadd 0, 8154ff2f60dSAdrian Chadd 1000); 8164ff2f60dSAdrian Chadd 8174ff2f60dSAdrian Chadd if (ret) 8184ff2f60dSAdrian Chadd device_printf(sc->sc_dev, "%s: waitreg failed\n", __func__); 8194ff2f60dSAdrian Chadd 8204ff2f60dSAdrian Chadd if (!ret) 8214ff2f60dSAdrian Chadd arswitch_writereg(sc->sc_dev, 8224ff2f60dSAdrian Chadd AR8327_REG_ATU_FUNC, 8234ff2f60dSAdrian Chadd AR8327_ATU_FUNC_OP_FLUSH); 8244ff2f60dSAdrian Chadd return (ret); 8254ff2f60dSAdrian Chadd } 8264ff2f60dSAdrian Chadd 8277330dd0bSAdrian Chadd void 8287330dd0bSAdrian Chadd ar8327_attach(struct arswitch_softc *sc) 8297330dd0bSAdrian Chadd { 8307330dd0bSAdrian Chadd 8317330dd0bSAdrian Chadd sc->hal.arswitch_hw_setup = ar8327_hw_setup; 8327330dd0bSAdrian Chadd sc->hal.arswitch_hw_global_setup = ar8327_hw_global_setup; 8337330dd0bSAdrian Chadd 8347330dd0bSAdrian Chadd sc->hal.arswitch_port_init = ar8327_port_init; 8357330dd0bSAdrian Chadd sc->hal.arswitch_port_vlan_setup = ar8327_port_vlan_setup; 8367330dd0bSAdrian Chadd sc->hal.arswitch_port_vlan_get = ar8327_port_vlan_get; 8377330dd0bSAdrian Chadd 8387330dd0bSAdrian Chadd sc->hal.arswitch_vlan_init_hw = ar8327_reset_vlans; 8397330dd0bSAdrian Chadd sc->hal.arswitch_vlan_getvgroup = ar8327_vlan_getvgroup; 8407330dd0bSAdrian Chadd sc->hal.arswitch_vlan_setvgroup = ar8327_vlan_setvgroup; 8417330dd0bSAdrian Chadd sc->hal.arswitch_vlan_get_pvid = ar8327_get_pvid; 8427330dd0bSAdrian Chadd sc->hal.arswitch_vlan_set_pvid = ar8327_set_pvid; 8437330dd0bSAdrian Chadd 8444ff2f60dSAdrian Chadd sc->hal.arswitch_atu_flush = ar8327_atu_flush; 8454ff2f60dSAdrian Chadd 8467330dd0bSAdrian Chadd /* Set the switch vlan capabilities. */ 8477330dd0bSAdrian Chadd sc->info.es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q | 8487330dd0bSAdrian Chadd ETHERSWITCH_VLAN_PORT | ETHERSWITCH_VLAN_DOUBLE_TAG; 8497330dd0bSAdrian Chadd sc->info.es_nvlangroups = AR8X16_MAX_VLANS; 8507330dd0bSAdrian Chadd } 851