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> 60*78549b94SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_phy.h> 61*78549b94SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_vlans.h> 62*78549b94SAdrian Chadd 637330dd0bSAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_8327.h> 647330dd0bSAdrian Chadd 657330dd0bSAdrian Chadd #include "mdio_if.h" 667330dd0bSAdrian Chadd #include "miibus_if.h" 677330dd0bSAdrian Chadd #include "etherswitch_if.h" 687330dd0bSAdrian Chadd 697330dd0bSAdrian Chadd static void 707330dd0bSAdrian Chadd ar8327_phy_fixup(struct arswitch_softc *sc, int phy) 717330dd0bSAdrian Chadd { 72db37238fSAdrian Chadd if (bootverbose) 73db37238fSAdrian Chadd device_printf(sc->sc_dev, 74db37238fSAdrian Chadd "%s: called; phy=%d; chiprev=%d\n", __func__, 75db37238fSAdrian Chadd phy, 76db37238fSAdrian Chadd sc->chip_rev); 777330dd0bSAdrian Chadd switch (sc->chip_rev) { 787330dd0bSAdrian Chadd case 1: 797330dd0bSAdrian Chadd /* For 100M waveform */ 807330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0, 0x02ea); 817330dd0bSAdrian Chadd /* Turn on Gigabit clock */ 827330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0x3d, 0x68a0); 837330dd0bSAdrian Chadd break; 847330dd0bSAdrian Chadd 857330dd0bSAdrian Chadd case 2: 867330dd0bSAdrian Chadd arswitch_writemmd(sc->sc_dev, phy, 0x7, 0x3c); 877330dd0bSAdrian Chadd arswitch_writemmd(sc->sc_dev, phy, 0x4007, 0x0); 887330dd0bSAdrian Chadd /* fallthrough */ 897330dd0bSAdrian Chadd case 4: 907330dd0bSAdrian Chadd arswitch_writemmd(sc->sc_dev, phy, 0x3, 0x800d); 917330dd0bSAdrian Chadd arswitch_writemmd(sc->sc_dev, phy, 0x4003, 0x803f); 927330dd0bSAdrian Chadd 937330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0x3d, 0x6860); 947330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0x5, 0x2c46); 957330dd0bSAdrian Chadd arswitch_writedbg(sc->sc_dev, phy, 0x3c, 0x6000); 967330dd0bSAdrian Chadd break; 977330dd0bSAdrian Chadd } 987330dd0bSAdrian Chadd } 997330dd0bSAdrian Chadd 1007330dd0bSAdrian Chadd static uint32_t 1017330dd0bSAdrian Chadd ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg) 1027330dd0bSAdrian Chadd { 1037330dd0bSAdrian Chadd uint32_t t; 1047330dd0bSAdrian Chadd 1057330dd0bSAdrian Chadd if (!cfg) 1067330dd0bSAdrian Chadd return (0); 1077330dd0bSAdrian Chadd 1087330dd0bSAdrian Chadd t = 0; 1097330dd0bSAdrian Chadd switch (cfg->mode) { 1107330dd0bSAdrian Chadd case AR8327_PAD_NC: 1117330dd0bSAdrian Chadd break; 1127330dd0bSAdrian Chadd 1137330dd0bSAdrian Chadd case AR8327_PAD_MAC2MAC_MII: 1147330dd0bSAdrian Chadd t = AR8327_PAD_MAC_MII_EN; 1157330dd0bSAdrian Chadd if (cfg->rxclk_sel) 1167330dd0bSAdrian Chadd t |= AR8327_PAD_MAC_MII_RXCLK_SEL; 1177330dd0bSAdrian Chadd if (cfg->txclk_sel) 1187330dd0bSAdrian Chadd t |= AR8327_PAD_MAC_MII_TXCLK_SEL; 1197330dd0bSAdrian Chadd break; 1207330dd0bSAdrian Chadd 1217330dd0bSAdrian Chadd case AR8327_PAD_MAC2MAC_GMII: 1227330dd0bSAdrian Chadd t = AR8327_PAD_MAC_GMII_EN; 1237330dd0bSAdrian Chadd if (cfg->rxclk_sel) 1247330dd0bSAdrian Chadd t |= AR8327_PAD_MAC_GMII_RXCLK_SEL; 1257330dd0bSAdrian Chadd if (cfg->txclk_sel) 1267330dd0bSAdrian Chadd t |= AR8327_PAD_MAC_GMII_TXCLK_SEL; 1277330dd0bSAdrian Chadd break; 1287330dd0bSAdrian Chadd 1297330dd0bSAdrian Chadd case AR8327_PAD_MAC_SGMII: 1307330dd0bSAdrian Chadd t = AR8327_PAD_SGMII_EN; 1317330dd0bSAdrian Chadd 1327330dd0bSAdrian Chadd /* 1339ab21e32SAdrian Chadd * WAR for the Qualcomm Atheros AP136 board. 1347330dd0bSAdrian Chadd * It seems that RGMII TX/RX delay settings needs to be 1357330dd0bSAdrian Chadd * applied for SGMII mode as well, The ethernet is not 1367330dd0bSAdrian Chadd * reliable without this. 1377330dd0bSAdrian Chadd */ 1387330dd0bSAdrian Chadd t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; 1397330dd0bSAdrian Chadd t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; 1407330dd0bSAdrian Chadd if (cfg->rxclk_delay_en) 1417330dd0bSAdrian Chadd t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; 1427330dd0bSAdrian Chadd if (cfg->txclk_delay_en) 1437330dd0bSAdrian Chadd t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; 1447330dd0bSAdrian Chadd 1457330dd0bSAdrian Chadd if (cfg->sgmii_delay_en) 1467330dd0bSAdrian Chadd t |= AR8327_PAD_SGMII_DELAY_EN; 1477330dd0bSAdrian Chadd 1487330dd0bSAdrian Chadd break; 1497330dd0bSAdrian Chadd 1507330dd0bSAdrian Chadd case AR8327_PAD_MAC2PHY_MII: 1517330dd0bSAdrian Chadd t = AR8327_PAD_PHY_MII_EN; 1527330dd0bSAdrian Chadd if (cfg->rxclk_sel) 1537330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_MII_RXCLK_SEL; 1547330dd0bSAdrian Chadd if (cfg->txclk_sel) 1557330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_MII_TXCLK_SEL; 1567330dd0bSAdrian Chadd break; 1577330dd0bSAdrian Chadd 1587330dd0bSAdrian Chadd case AR8327_PAD_MAC2PHY_GMII: 1597330dd0bSAdrian Chadd t = AR8327_PAD_PHY_GMII_EN; 1607330dd0bSAdrian Chadd if (cfg->pipe_rxclk_sel) 1617330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL; 1627330dd0bSAdrian Chadd if (cfg->rxclk_sel) 1637330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_GMII_RXCLK_SEL; 1647330dd0bSAdrian Chadd if (cfg->txclk_sel) 1657330dd0bSAdrian Chadd t |= AR8327_PAD_PHY_GMII_TXCLK_SEL; 1667330dd0bSAdrian Chadd break; 1677330dd0bSAdrian Chadd 1687330dd0bSAdrian Chadd case AR8327_PAD_MAC_RGMII: 1697330dd0bSAdrian Chadd t = AR8327_PAD_RGMII_EN; 1707330dd0bSAdrian Chadd t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; 1717330dd0bSAdrian Chadd t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; 1727330dd0bSAdrian Chadd if (cfg->rxclk_delay_en) 1737330dd0bSAdrian Chadd t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; 1747330dd0bSAdrian Chadd if (cfg->txclk_delay_en) 1757330dd0bSAdrian Chadd t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; 1767330dd0bSAdrian Chadd break; 1777330dd0bSAdrian Chadd 1787330dd0bSAdrian Chadd case AR8327_PAD_PHY_GMII: 1797330dd0bSAdrian Chadd t = AR8327_PAD_PHYX_GMII_EN; 1807330dd0bSAdrian Chadd break; 1817330dd0bSAdrian Chadd 1827330dd0bSAdrian Chadd case AR8327_PAD_PHY_RGMII: 1837330dd0bSAdrian Chadd t = AR8327_PAD_PHYX_RGMII_EN; 1847330dd0bSAdrian Chadd break; 1857330dd0bSAdrian Chadd 1867330dd0bSAdrian Chadd case AR8327_PAD_PHY_MII: 1877330dd0bSAdrian Chadd t = AR8327_PAD_PHYX_MII_EN; 1887330dd0bSAdrian Chadd break; 1897330dd0bSAdrian Chadd } 1907330dd0bSAdrian Chadd 1917330dd0bSAdrian Chadd return (t); 1927330dd0bSAdrian Chadd } 1937330dd0bSAdrian Chadd 1947330dd0bSAdrian Chadd /* 1957330dd0bSAdrian Chadd * Map the hard-coded port config from the switch setup to 1967330dd0bSAdrian Chadd * the chipset port config (status, duplex, flow, etc.) 1977330dd0bSAdrian Chadd */ 1987330dd0bSAdrian Chadd static uint32_t 1997330dd0bSAdrian Chadd ar8327_get_port_init_status(struct ar8327_port_cfg *cfg) 2007330dd0bSAdrian Chadd { 2017330dd0bSAdrian Chadd uint32_t t; 2027330dd0bSAdrian Chadd 2037330dd0bSAdrian Chadd if (!cfg->force_link) 2047330dd0bSAdrian Chadd return (AR8X16_PORT_STS_LINK_AUTO); 2057330dd0bSAdrian Chadd 2067330dd0bSAdrian Chadd t = AR8X16_PORT_STS_TXMAC | AR8X16_PORT_STS_RXMAC; 2077330dd0bSAdrian Chadd t |= cfg->duplex ? AR8X16_PORT_STS_DUPLEX : 0; 2087330dd0bSAdrian Chadd t |= cfg->rxpause ? AR8X16_PORT_STS_RXFLOW : 0; 2097330dd0bSAdrian Chadd t |= cfg->txpause ? AR8X16_PORT_STS_TXFLOW : 0; 2107330dd0bSAdrian Chadd 2117330dd0bSAdrian Chadd switch (cfg->speed) { 2127330dd0bSAdrian Chadd case AR8327_PORT_SPEED_10: 2137330dd0bSAdrian Chadd t |= AR8X16_PORT_STS_SPEED_10; 2147330dd0bSAdrian Chadd break; 2157330dd0bSAdrian Chadd case AR8327_PORT_SPEED_100: 2167330dd0bSAdrian Chadd t |= AR8X16_PORT_STS_SPEED_100; 2177330dd0bSAdrian Chadd break; 2187330dd0bSAdrian Chadd case AR8327_PORT_SPEED_1000: 2197330dd0bSAdrian Chadd t |= AR8X16_PORT_STS_SPEED_1000; 2207330dd0bSAdrian Chadd break; 2217330dd0bSAdrian Chadd } 2227330dd0bSAdrian Chadd 2237330dd0bSAdrian Chadd return (t); 2247330dd0bSAdrian Chadd } 2259ab21e32SAdrian Chadd 2269ab21e32SAdrian Chadd /* 227f9950f9aSAdrian Chadd * Fetch the port data for the given port. 228f9950f9aSAdrian Chadd * 229f9950f9aSAdrian Chadd * This goes and does dirty things with the hints space 230f9950f9aSAdrian Chadd * to determine what the configuration parameters should be. 231f9950f9aSAdrian Chadd * 232f9950f9aSAdrian Chadd * Returns 1 if the structure was successfully parsed and 233f9950f9aSAdrian Chadd * the contents are valid; 0 otherwise. 234f9950f9aSAdrian Chadd */ 235f9950f9aSAdrian Chadd static int 236f9950f9aSAdrian Chadd ar8327_fetch_pdata_port(struct arswitch_softc *sc, 237f9950f9aSAdrian Chadd struct ar8327_port_cfg *pcfg, 238f9950f9aSAdrian Chadd int port) 239f9950f9aSAdrian Chadd { 240f9950f9aSAdrian Chadd int val; 241f9950f9aSAdrian Chadd char sbuf[128]; 242f9950f9aSAdrian Chadd 243f9950f9aSAdrian Chadd /* Check if force_link exists */ 244f9950f9aSAdrian Chadd val = 0; 245f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.force_link", port); 246f9950f9aSAdrian Chadd (void) resource_int_value(device_get_name(sc->sc_dev), 247f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 248f9950f9aSAdrian Chadd sbuf, &val); 249f9950f9aSAdrian Chadd if (val != 1) 250f9950f9aSAdrian Chadd return (0); 251f9950f9aSAdrian Chadd pcfg->force_link = 1; 252f9950f9aSAdrian Chadd 253f9950f9aSAdrian Chadd /* force_link is set; let's parse the rest of the fields */ 254f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.speed", port); 255f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 256f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 257f9950f9aSAdrian Chadd sbuf, &val) == 0) { 258f9950f9aSAdrian Chadd switch (val) { 259f9950f9aSAdrian Chadd case 10: 260f9950f9aSAdrian Chadd pcfg->speed = AR8327_PORT_SPEED_10; 261f9950f9aSAdrian Chadd break; 262f9950f9aSAdrian Chadd case 100: 263f9950f9aSAdrian Chadd pcfg->speed = AR8327_PORT_SPEED_100; 264f9950f9aSAdrian Chadd break; 265f9950f9aSAdrian Chadd case 1000: 266f9950f9aSAdrian Chadd pcfg->speed = AR8327_PORT_SPEED_1000; 267f9950f9aSAdrian Chadd break; 268f9950f9aSAdrian Chadd default: 269f9950f9aSAdrian Chadd device_printf(sc->sc_dev, 270f9950f9aSAdrian Chadd "%s: invalid port %d duplex value (%d)\n", 271f9950f9aSAdrian Chadd __func__, 272f9950f9aSAdrian Chadd port, 273f9950f9aSAdrian Chadd val); 274f9950f9aSAdrian Chadd return (0); 275f9950f9aSAdrian Chadd } 276f9950f9aSAdrian Chadd } 277f9950f9aSAdrian Chadd 278f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.duplex", port); 279f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 280f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 281f9950f9aSAdrian Chadd sbuf, &val) == 0) 282f9950f9aSAdrian Chadd pcfg->duplex = val; 283f9950f9aSAdrian Chadd 284f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.txpause", port); 285f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 286f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 287f9950f9aSAdrian Chadd sbuf, &val) == 0) 288f9950f9aSAdrian Chadd pcfg->txpause = val; 289f9950f9aSAdrian Chadd 290f9950f9aSAdrian Chadd snprintf(sbuf, 128, "port.%d.rxpause", port); 291f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 292f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 293f9950f9aSAdrian Chadd sbuf, &val) == 0) 294f9950f9aSAdrian Chadd pcfg->rxpause = val; 295f9950f9aSAdrian Chadd 296*78549b94SAdrian Chadd #if 1 297f9950f9aSAdrian Chadd device_printf(sc->sc_dev, 298f9950f9aSAdrian Chadd "%s: port %d: speed=%d, duplex=%d, txpause=%d, rxpause=%d\n", 299f9950f9aSAdrian Chadd __func__, 300f9950f9aSAdrian Chadd port, 301f9950f9aSAdrian Chadd pcfg->speed, 302f9950f9aSAdrian Chadd pcfg->duplex, 303f9950f9aSAdrian Chadd pcfg->txpause, 304f9950f9aSAdrian Chadd pcfg->rxpause); 305f9950f9aSAdrian Chadd #endif 306f9950f9aSAdrian Chadd 307f9950f9aSAdrian Chadd return (1); 308f9950f9aSAdrian Chadd } 309f9950f9aSAdrian Chadd 310f9950f9aSAdrian Chadd /* 311f9950f9aSAdrian Chadd * Parse the pad configuration from the boot hints. 312f9950f9aSAdrian Chadd * 313f9950f9aSAdrian Chadd * The (mostly optional) fields are: 314f9950f9aSAdrian Chadd * 315f9950f9aSAdrian Chadd * uint32_t mode; 316f9950f9aSAdrian Chadd * uint32_t rxclk_sel; 317f9950f9aSAdrian Chadd * uint32_t txclk_sel; 318f9950f9aSAdrian Chadd * uint32_t txclk_delay_sel; 319f9950f9aSAdrian Chadd * uint32_t rxclk_delay_sel; 320f9950f9aSAdrian Chadd * uint32_t txclk_delay_en; 321f9950f9aSAdrian Chadd * uint32_t rxclk_delay_en; 322f9950f9aSAdrian Chadd * uint32_t sgmii_delay_en; 323f9950f9aSAdrian Chadd * uint32_t pipe_rxclk_sel; 324f9950f9aSAdrian Chadd * 325f9950f9aSAdrian Chadd * If mode isn't in the hints, 0 is returned. 326f9950f9aSAdrian Chadd * Else the structure is fleshed out and 1 is returned. 327f9950f9aSAdrian Chadd */ 328f9950f9aSAdrian Chadd static int 329f9950f9aSAdrian Chadd ar8327_fetch_pdata_pad(struct arswitch_softc *sc, 330f9950f9aSAdrian Chadd struct ar8327_pad_cfg *pc, 331f9950f9aSAdrian Chadd int pad) 332f9950f9aSAdrian Chadd { 333f9950f9aSAdrian Chadd int val; 334f9950f9aSAdrian Chadd char sbuf[128]; 335f9950f9aSAdrian Chadd 336f9950f9aSAdrian Chadd /* Check if mode exists */ 337f9950f9aSAdrian Chadd val = 0; 338f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.mode", pad); 339f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 340f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 341f9950f9aSAdrian Chadd sbuf, &val) != 0) 342f9950f9aSAdrian Chadd return (0); 343f9950f9aSAdrian Chadd 344f9950f9aSAdrian Chadd /* assume that 'mode' exists and was found */ 345f9950f9aSAdrian Chadd pc->mode = val; 346f9950f9aSAdrian Chadd 347f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.rxclk_sel", pad); 348f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 349f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 350f9950f9aSAdrian Chadd sbuf, &val) == 0) 351f9950f9aSAdrian Chadd pc->rxclk_sel = val; 352f9950f9aSAdrian Chadd 353f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.txclk_sel", pad); 354f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 355f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 356f9950f9aSAdrian Chadd sbuf, &val) == 0) 357f9950f9aSAdrian Chadd pc->txclk_sel = val; 358f9950f9aSAdrian Chadd 359f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.txclk_delay_sel", pad); 360f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 361f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 362f9950f9aSAdrian Chadd sbuf, &val) == 0) 363f9950f9aSAdrian Chadd pc->txclk_delay_sel = val; 364f9950f9aSAdrian Chadd 365f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.rxclk_delay_sel", pad); 366f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 367f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 368f9950f9aSAdrian Chadd sbuf, &val) == 0) 369f9950f9aSAdrian Chadd pc->rxclk_delay_sel = val; 370f9950f9aSAdrian Chadd 371f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.txclk_delay_en", pad); 372f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 373f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 374f9950f9aSAdrian Chadd sbuf, &val) == 0) 375f9950f9aSAdrian Chadd pc->txclk_delay_en = val; 376f9950f9aSAdrian Chadd 377f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.rxclk_delay_en", pad); 378f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 379f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 380f9950f9aSAdrian Chadd sbuf, &val) == 0) 381f9950f9aSAdrian Chadd pc->rxclk_delay_en = val; 382f9950f9aSAdrian Chadd 383f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.sgmii_delay_en", pad); 384f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 385f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 386f9950f9aSAdrian Chadd sbuf, &val) == 0) 387f9950f9aSAdrian Chadd pc->sgmii_delay_en = val; 388f9950f9aSAdrian Chadd 389f9950f9aSAdrian Chadd snprintf(sbuf, 128, "pad.%d.pipe_rxclk_sel", pad); 390f9950f9aSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 391f9950f9aSAdrian Chadd device_get_unit(sc->sc_dev), 392f9950f9aSAdrian Chadd sbuf, &val) == 0) 393f9950f9aSAdrian Chadd pc->pipe_rxclk_sel = val; 394f9950f9aSAdrian Chadd 395db37238fSAdrian Chadd if (bootverbose) { 396f9950f9aSAdrian Chadd device_printf(sc->sc_dev, 397f9950f9aSAdrian Chadd "%s: pad %d: mode=%d, rxclk_sel=%d, txclk_sel=%d, " 398f9950f9aSAdrian Chadd "txclk_delay_sel=%d, rxclk_delay_sel=%d, txclk_delay_en=%d, " 399f9950f9aSAdrian Chadd "rxclk_enable_en=%d, sgmii_delay_en=%d, pipe_rxclk_sel=%d\n", 400f9950f9aSAdrian Chadd __func__, 401f9950f9aSAdrian Chadd pad, 402f9950f9aSAdrian Chadd pc->mode, 403f9950f9aSAdrian Chadd pc->rxclk_sel, 404f9950f9aSAdrian Chadd pc->txclk_sel, 405f9950f9aSAdrian Chadd pc->txclk_delay_sel, 406f9950f9aSAdrian Chadd pc->rxclk_delay_sel, 407f9950f9aSAdrian Chadd pc->txclk_delay_en, 408f9950f9aSAdrian Chadd pc->rxclk_delay_en, 409f9950f9aSAdrian Chadd pc->sgmii_delay_en, 410f9950f9aSAdrian Chadd pc->pipe_rxclk_sel); 411db37238fSAdrian Chadd } 412f9950f9aSAdrian Chadd 413f9950f9aSAdrian Chadd return (1); 414f9950f9aSAdrian Chadd } 415f9950f9aSAdrian Chadd 416f9950f9aSAdrian Chadd /* 417810bdeddSAdrian Chadd * Fetch the SGMII configuration block from the boot hints. 418810bdeddSAdrian Chadd */ 419810bdeddSAdrian Chadd static int 420810bdeddSAdrian Chadd ar8327_fetch_pdata_sgmii(struct arswitch_softc *sc, 421810bdeddSAdrian Chadd struct ar8327_sgmii_cfg *scfg) 422810bdeddSAdrian Chadd { 423810bdeddSAdrian Chadd int val; 424810bdeddSAdrian Chadd 425810bdeddSAdrian Chadd /* sgmii_ctrl */ 426810bdeddSAdrian Chadd val = 0; 427810bdeddSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 428810bdeddSAdrian Chadd device_get_unit(sc->sc_dev), 429810bdeddSAdrian Chadd "sgmii.ctrl", &val) != 0) 430810bdeddSAdrian Chadd return (0); 431810bdeddSAdrian Chadd scfg->sgmii_ctrl = val; 432810bdeddSAdrian Chadd 433810bdeddSAdrian Chadd /* serdes_aen */ 434810bdeddSAdrian Chadd val = 0; 435810bdeddSAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 436810bdeddSAdrian Chadd device_get_unit(sc->sc_dev), 437810bdeddSAdrian Chadd "sgmii.serdes_aen", &val) != 0) 438810bdeddSAdrian Chadd return (0); 439810bdeddSAdrian Chadd scfg->serdes_aen = val; 440810bdeddSAdrian Chadd 441810bdeddSAdrian Chadd return (1); 442810bdeddSAdrian Chadd } 443810bdeddSAdrian Chadd 444810bdeddSAdrian Chadd /* 445b67ba111SAdrian Chadd * Fetch the LED configuration from the boot hints. 446b67ba111SAdrian Chadd */ 447b67ba111SAdrian Chadd static int 448b67ba111SAdrian Chadd ar8327_fetch_pdata_led(struct arswitch_softc *sc, 449b67ba111SAdrian Chadd struct ar8327_led_cfg *lcfg) 450b67ba111SAdrian Chadd { 451b67ba111SAdrian Chadd int val; 452b67ba111SAdrian Chadd 453b67ba111SAdrian Chadd val = 0; 454b67ba111SAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 455b67ba111SAdrian Chadd device_get_unit(sc->sc_dev), 456b67ba111SAdrian Chadd "led.ctrl0", &val) != 0) 457b67ba111SAdrian Chadd return (0); 458b67ba111SAdrian Chadd lcfg->led_ctrl0 = val; 459b67ba111SAdrian Chadd 460b67ba111SAdrian Chadd val = 0; 461b67ba111SAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 462b67ba111SAdrian Chadd device_get_unit(sc->sc_dev), 463b67ba111SAdrian Chadd "led.ctrl1", &val) != 0) 464b67ba111SAdrian Chadd return (0); 465b67ba111SAdrian Chadd lcfg->led_ctrl1 = val; 466b67ba111SAdrian Chadd 467b67ba111SAdrian Chadd val = 0; 468b67ba111SAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 469b67ba111SAdrian Chadd device_get_unit(sc->sc_dev), 470b67ba111SAdrian Chadd "led.ctrl2", &val) != 0) 471b67ba111SAdrian Chadd return (0); 472b67ba111SAdrian Chadd lcfg->led_ctrl2 = val; 473b67ba111SAdrian Chadd 474b67ba111SAdrian Chadd val = 0; 475b67ba111SAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 476b67ba111SAdrian Chadd device_get_unit(sc->sc_dev), 477b67ba111SAdrian Chadd "led.ctrl3", &val) != 0) 478b67ba111SAdrian Chadd return (0); 479b67ba111SAdrian Chadd lcfg->led_ctrl3 = val; 480b67ba111SAdrian Chadd 481b67ba111SAdrian Chadd val = 0; 482b67ba111SAdrian Chadd if (resource_int_value(device_get_name(sc->sc_dev), 483b67ba111SAdrian Chadd device_get_unit(sc->sc_dev), 484b67ba111SAdrian Chadd "led.open_drain", &val) != 0) 485b67ba111SAdrian Chadd return (0); 486b67ba111SAdrian Chadd lcfg->open_drain = val; 487b67ba111SAdrian Chadd 488b67ba111SAdrian Chadd return (1); 489b67ba111SAdrian Chadd } 490b67ba111SAdrian Chadd 491b67ba111SAdrian Chadd /* 4929ab21e32SAdrian Chadd * Initialise the ar8327 specific hardware features from 4939ab21e32SAdrian Chadd * the hints provided in the boot environment. 4949ab21e32SAdrian Chadd */ 4959ab21e32SAdrian Chadd static int 4969ab21e32SAdrian Chadd ar8327_init_pdata(struct arswitch_softc *sc) 4979ab21e32SAdrian Chadd { 4989ab21e32SAdrian Chadd struct ar8327_pad_cfg pc; 4999ab21e32SAdrian Chadd struct ar8327_port_cfg port_cfg; 500810bdeddSAdrian Chadd struct ar8327_sgmii_cfg scfg; 501b67ba111SAdrian Chadd struct ar8327_led_cfg lcfg; 502810bdeddSAdrian Chadd uint32_t t, new_pos, pos; 5039ab21e32SAdrian Chadd 504f9950f9aSAdrian Chadd /* Port 0 */ 5059ab21e32SAdrian Chadd bzero(&port_cfg, sizeof(port_cfg)); 506f9950f9aSAdrian Chadd sc->ar8327.port0_status = 0; 507f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_port(sc, &port_cfg, 0)) 5089ab21e32SAdrian Chadd sc->ar8327.port0_status = ar8327_get_port_init_status(&port_cfg); 5099ab21e32SAdrian Chadd 510f9950f9aSAdrian Chadd /* Port 6 */ 5119ab21e32SAdrian Chadd bzero(&port_cfg, sizeof(port_cfg)); 512f9950f9aSAdrian Chadd sc->ar8327.port6_status = 0; 513f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_port(sc, &port_cfg, 6)) 5149ab21e32SAdrian Chadd sc->ar8327.port6_status = ar8327_get_port_init_status(&port_cfg); 5159ab21e32SAdrian Chadd 5169ab21e32SAdrian Chadd /* Pad 0 */ 5179ab21e32SAdrian Chadd bzero(&pc, sizeof(pc)); 518f9950f9aSAdrian Chadd t = 0; 519f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_pad(sc, &pc, 0)) 5209ab21e32SAdrian Chadd t = ar8327_get_pad_cfg(&pc); 5219ab21e32SAdrian Chadd #if 0 5229ab21e32SAdrian Chadd if (AR8X16_IS_SWITCH(sc, AR8337)) 5239ab21e32SAdrian Chadd t |= AR8337_PAD_MAC06_EXCHANGE_EN; 5247330dd0bSAdrian Chadd #endif 5259ab21e32SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PAD0_MODE, t); 5269ab21e32SAdrian Chadd 5279ab21e32SAdrian Chadd /* Pad 5 */ 5289ab21e32SAdrian Chadd bzero(&pc, sizeof(pc)); 529f9950f9aSAdrian Chadd t = 0; 530f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_pad(sc, &pc, 5)) 5319ab21e32SAdrian Chadd t = ar8327_get_pad_cfg(&pc); 5329ab21e32SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PAD5_MODE, t); 5339ab21e32SAdrian Chadd 5349ab21e32SAdrian Chadd /* Pad 6 */ 5359ab21e32SAdrian Chadd bzero(&pc, sizeof(pc)); 536f9950f9aSAdrian Chadd t = 0; 537f9950f9aSAdrian Chadd if (ar8327_fetch_pdata_pad(sc, &pc, 6)) 5389ab21e32SAdrian Chadd t = ar8327_get_pad_cfg(&pc); 5399ab21e32SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PAD6_MODE, t); 5409ab21e32SAdrian Chadd 541810bdeddSAdrian Chadd pos = arswitch_readreg(sc->sc_dev, AR8327_REG_POWER_ON_STRIP); 542810bdeddSAdrian Chadd new_pos = pos; 543810bdeddSAdrian Chadd 5449ab21e32SAdrian Chadd /* XXX LED config */ 545b67ba111SAdrian Chadd bzero(&lcfg, sizeof(lcfg)); 546b67ba111SAdrian Chadd if (ar8327_fetch_pdata_led(sc, &lcfg)) { 547b67ba111SAdrian Chadd if (lcfg.open_drain) 548b67ba111SAdrian Chadd new_pos |= AR8327_POWER_ON_STRIP_LED_OPEN_EN; 549b67ba111SAdrian Chadd else 550b67ba111SAdrian Chadd new_pos &= ~AR8327_POWER_ON_STRIP_LED_OPEN_EN; 551b67ba111SAdrian Chadd 552b67ba111SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_LED_CTRL0, 553b67ba111SAdrian Chadd lcfg.led_ctrl0); 554b67ba111SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_LED_CTRL1, 555b67ba111SAdrian Chadd lcfg.led_ctrl1); 556b67ba111SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_LED_CTRL2, 557b67ba111SAdrian Chadd lcfg.led_ctrl2); 558b67ba111SAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_LED_CTRL3, 559b67ba111SAdrian Chadd lcfg.led_ctrl3); 560b67ba111SAdrian Chadd 561b67ba111SAdrian Chadd if (new_pos != pos) 562b67ba111SAdrian Chadd new_pos |= AR8327_POWER_ON_STRIP_POWER_ON_SEL; 563b67ba111SAdrian Chadd } 5649ab21e32SAdrian Chadd 565810bdeddSAdrian Chadd /* SGMII config */ 566810bdeddSAdrian Chadd bzero(&scfg, sizeof(scfg)); 567810bdeddSAdrian Chadd if (ar8327_fetch_pdata_sgmii(sc, &scfg)) { 568*78549b94SAdrian Chadd device_printf(sc->sc_dev, "%s: SGMII cfg?\n", __func__); 569810bdeddSAdrian Chadd t = scfg.sgmii_ctrl; 570810bdeddSAdrian Chadd if (sc->chip_rev == 1) 571810bdeddSAdrian Chadd t |= AR8327_SGMII_CTRL_EN_PLL | 572810bdeddSAdrian Chadd AR8327_SGMII_CTRL_EN_RX | 573810bdeddSAdrian Chadd AR8327_SGMII_CTRL_EN_TX; 574810bdeddSAdrian Chadd else 575810bdeddSAdrian Chadd t &= ~(AR8327_SGMII_CTRL_EN_PLL | 576810bdeddSAdrian Chadd AR8327_SGMII_CTRL_EN_RX | 577810bdeddSAdrian Chadd AR8327_SGMII_CTRL_EN_TX); 578810bdeddSAdrian Chadd 579810bdeddSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_SGMII_CTRL, t); 580810bdeddSAdrian Chadd 581810bdeddSAdrian Chadd if (scfg.serdes_aen) 582810bdeddSAdrian Chadd new_pos &= ~AR8327_POWER_ON_STRIP_SERDES_AEN; 583810bdeddSAdrian Chadd else 584810bdeddSAdrian Chadd new_pos |= AR8327_POWER_ON_STRIP_SERDES_AEN; 585810bdeddSAdrian Chadd } 586810bdeddSAdrian Chadd 587810bdeddSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_POWER_ON_STRIP, new_pos); 5889ab21e32SAdrian Chadd 5899ab21e32SAdrian Chadd return (0); 5909ab21e32SAdrian Chadd } 5917330dd0bSAdrian Chadd 5927330dd0bSAdrian Chadd static int 5937330dd0bSAdrian Chadd ar8327_hw_setup(struct arswitch_softc *sc) 5947330dd0bSAdrian Chadd { 5957330dd0bSAdrian Chadd int i; 5967330dd0bSAdrian Chadd int err; 5977330dd0bSAdrian Chadd 5987330dd0bSAdrian Chadd /* pdata fetch and setup */ 5997330dd0bSAdrian Chadd err = ar8327_init_pdata(sc); 6007330dd0bSAdrian Chadd if (err != 0) 6017330dd0bSAdrian Chadd return (err); 6027330dd0bSAdrian Chadd 6037330dd0bSAdrian Chadd /* XXX init leds */ 6047330dd0bSAdrian Chadd 6057330dd0bSAdrian Chadd for (i = 0; i < AR8327_NUM_PHYS; i++) { 6067330dd0bSAdrian Chadd /* phy fixup */ 6077330dd0bSAdrian Chadd ar8327_phy_fixup(sc, i); 6087330dd0bSAdrian Chadd 6097330dd0bSAdrian Chadd /* start PHY autonegotiation? */ 6107330dd0bSAdrian Chadd /* XXX is this done as part of the normal PHY setup? */ 6117330dd0bSAdrian Chadd 6127330dd0bSAdrian Chadd }; 6137330dd0bSAdrian Chadd 6147330dd0bSAdrian Chadd /* Let things settle */ 6157330dd0bSAdrian Chadd DELAY(1000); 6167330dd0bSAdrian Chadd 6177330dd0bSAdrian Chadd return (0); 6187330dd0bSAdrian Chadd } 6197330dd0bSAdrian Chadd 6207330dd0bSAdrian Chadd /* 6217330dd0bSAdrian Chadd * Initialise other global values, for the AR8327. 6227330dd0bSAdrian Chadd */ 6237330dd0bSAdrian Chadd static int 6247330dd0bSAdrian Chadd ar8327_hw_global_setup(struct arswitch_softc *sc) 6257330dd0bSAdrian Chadd { 6267330dd0bSAdrian Chadd uint32_t t; 6277330dd0bSAdrian Chadd 6287330dd0bSAdrian Chadd /* enable CPU port and disable mirror port */ 6297330dd0bSAdrian Chadd t = AR8327_FWD_CTRL0_CPU_PORT_EN | 6307330dd0bSAdrian Chadd AR8327_FWD_CTRL0_MIRROR_PORT; 6317330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_FWD_CTRL0, t); 6327330dd0bSAdrian Chadd 6337330dd0bSAdrian Chadd /* forward multicast and broadcast frames to CPU */ 6347330dd0bSAdrian Chadd t = (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_UC_FLOOD_S) | 6357330dd0bSAdrian Chadd (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_MC_FLOOD_S) | 6367330dd0bSAdrian Chadd (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_BC_FLOOD_S); 6377330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_FWD_CTRL1, t); 6387330dd0bSAdrian Chadd 6397330dd0bSAdrian Chadd /* enable jumbo frames */ 6407330dd0bSAdrian Chadd /* XXX need to macro-shift the value! */ 6417330dd0bSAdrian Chadd arswitch_modifyreg(sc->sc_dev, AR8327_REG_MAX_FRAME_SIZE, 6427330dd0bSAdrian Chadd AR8327_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2); 6437330dd0bSAdrian Chadd 6447330dd0bSAdrian Chadd /* Enable MIB counters */ 6457330dd0bSAdrian Chadd arswitch_modifyreg(sc->sc_dev, AR8327_REG_MODULE_EN, 6467330dd0bSAdrian Chadd AR8327_MODULE_EN_MIB, AR8327_MODULE_EN_MIB); 6477330dd0bSAdrian Chadd 648db37238fSAdrian Chadd /* Disable EEE on all ports due to stability issues */ 649db37238fSAdrian Chadd t = arswitch_readreg(sc->sc_dev, AR8327_REG_EEE_CTRL); 650db37238fSAdrian Chadd t |= AR8327_EEE_CTRL_DISABLE_PHY(0) | 651db37238fSAdrian Chadd AR8327_EEE_CTRL_DISABLE_PHY(1) | 652db37238fSAdrian Chadd AR8327_EEE_CTRL_DISABLE_PHY(2) | 653db37238fSAdrian Chadd AR8327_EEE_CTRL_DISABLE_PHY(3) | 654db37238fSAdrian Chadd AR8327_EEE_CTRL_DISABLE_PHY(4); 655db37238fSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_EEE_CTRL, t); 656db37238fSAdrian Chadd 6574ff2f60dSAdrian Chadd /* Set the right number of ports */ 6584ff2f60dSAdrian Chadd sc->info.es_nports = 6; 6594ff2f60dSAdrian Chadd 6607330dd0bSAdrian Chadd return (0); 6617330dd0bSAdrian Chadd } 6627330dd0bSAdrian Chadd 6637330dd0bSAdrian Chadd /* 664*78549b94SAdrian Chadd * Port setup. Called at attach time. 6657330dd0bSAdrian Chadd */ 6667330dd0bSAdrian Chadd static void 6677330dd0bSAdrian Chadd ar8327_port_init(struct arswitch_softc *sc, int port) 6687330dd0bSAdrian Chadd { 6697330dd0bSAdrian Chadd uint32_t t; 670*78549b94SAdrian Chadd int ports; 671*78549b94SAdrian Chadd 672*78549b94SAdrian Chadd /* For now, port can see all other ports */ 673*78549b94SAdrian Chadd ports = 0x7f; 6747330dd0bSAdrian Chadd 6759ab21e32SAdrian Chadd if (port == AR8X16_PORT_CPU) 6769ab21e32SAdrian Chadd t = sc->ar8327.port0_status; 6777330dd0bSAdrian Chadd else if (port == 6) 6789ab21e32SAdrian Chadd t = sc->ar8327.port6_status; 6797330dd0bSAdrian Chadd else 6807330dd0bSAdrian Chadd t = AR8X16_PORT_STS_LINK_AUTO; 6817330dd0bSAdrian Chadd 6827330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_STATUS(port), t); 6837330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_HEADER(port), 0); 6847330dd0bSAdrian Chadd 6850d2041a0SAdrian Chadd /* 6860d2041a0SAdrian Chadd * Default to 1 port group. 6870d2041a0SAdrian Chadd */ 6887330dd0bSAdrian Chadd t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S; 6897330dd0bSAdrian Chadd t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S; 6907330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN0(port), t); 6917330dd0bSAdrian Chadd 6927330dd0bSAdrian Chadd t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S; 6937330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN1(port), t); 6947330dd0bSAdrian Chadd 69503b5d827SAdrian Chadd /* 69603b5d827SAdrian Chadd * This doesn't configure any ports which this port can "see". 69703b5d827SAdrian Chadd * bits 0-6 control which ports a frame coming into this port 69803b5d827SAdrian Chadd * can be sent out to. 69903b5d827SAdrian Chadd * 70003b5d827SAdrian Chadd * So by doing this, we're making it impossible to send frames out 70103b5d827SAdrian Chadd * to that port. 70203b5d827SAdrian Chadd */ 7037330dd0bSAdrian Chadd t = AR8327_PORT_LOOKUP_LEARN; 7047330dd0bSAdrian Chadd t |= AR8X16_PORT_CTRL_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; 70503b5d827SAdrian Chadd 70603b5d827SAdrian Chadd /* So this allows traffic to any port except ourselves */ 707*78549b94SAdrian Chadd t |= (ports & ~(1 << port)); 7087330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(port), t); 7097330dd0bSAdrian Chadd } 7107330dd0bSAdrian Chadd 7117330dd0bSAdrian Chadd static int 7127330dd0bSAdrian Chadd ar8327_port_vlan_setup(struct arswitch_softc *sc, etherswitch_port_t *p) 7137330dd0bSAdrian Chadd { 7147330dd0bSAdrian Chadd 7157330dd0bSAdrian Chadd /* XXX stub for now */ 716*78549b94SAdrian Chadd // device_printf(sc->sc_dev, "%s: called\n", __func__); 7177330dd0bSAdrian Chadd return (0); 7187330dd0bSAdrian Chadd } 7197330dd0bSAdrian Chadd 720*78549b94SAdrian Chadd /* 721*78549b94SAdrian Chadd * Get the port VLAN configuration. 722*78549b94SAdrian Chadd */ 7237330dd0bSAdrian Chadd static int 7247330dd0bSAdrian Chadd ar8327_port_vlan_get(struct arswitch_softc *sc, etherswitch_port_t *p) 7257330dd0bSAdrian Chadd { 7267330dd0bSAdrian Chadd /* XXX stub for now */ 727*78549b94SAdrian Chadd // device_printf(sc->sc_dev, "%s: called\n", __func__); 7287330dd0bSAdrian Chadd return (0); 7297330dd0bSAdrian Chadd } 7307330dd0bSAdrian Chadd 7317330dd0bSAdrian Chadd static void 7327330dd0bSAdrian Chadd ar8327_reset_vlans(struct arswitch_softc *sc) 7337330dd0bSAdrian Chadd { 7347330dd0bSAdrian Chadd int i; 7357330dd0bSAdrian Chadd uint32_t mode, t; 736*78549b94SAdrian Chadd int ports; 737*78549b94SAdrian Chadd 738*78549b94SAdrian Chadd ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 739*78549b94SAdrian Chadd ARSWITCH_LOCK(sc); 740*78549b94SAdrian Chadd 741*78549b94SAdrian Chadd /* Clear the existing VLAN configuration */ 742*78549b94SAdrian Chadd memset(sc->vid, 0, sizeof(sc->vid)); 7437330dd0bSAdrian Chadd 7447330dd0bSAdrian Chadd /* 74503b5d827SAdrian Chadd * Disable mirroring. 74603b5d827SAdrian Chadd */ 74703b5d827SAdrian Chadd arswitch_modifyreg(sc->sc_dev, AR8327_REG_FWD_CTRL0, 74803b5d827SAdrian Chadd AR8327_FWD_CTRL0_MIRROR_PORT, 74903b5d827SAdrian Chadd (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S)); 75003b5d827SAdrian Chadd 75103b5d827SAdrian Chadd /* 752*78549b94SAdrian Chadd * XXX TODO: disable any Q-in-Q port configuration, 753*78549b94SAdrian Chadd * tagging, egress filters, etc. 7547330dd0bSAdrian Chadd */ 755*78549b94SAdrian Chadd 756*78549b94SAdrian Chadd /* 757*78549b94SAdrian Chadd * For now, let's default to one portgroup, just so traffic 758*78549b94SAdrian Chadd * flows. All ports can see other ports. There are two CPU GMACs 759*78549b94SAdrian Chadd * (GMAC0, GMAC6), GMAC1..GMAC5 are external PHYs. 760*78549b94SAdrian Chadd * 761*78549b94SAdrian Chadd * (ETHERSWITCH_VLAN_PORT) 762*78549b94SAdrian Chadd */ 763*78549b94SAdrian Chadd ports = 0x7f; 764*78549b94SAdrian Chadd 7657330dd0bSAdrian Chadd for (i = 0; i < AR8327_NUM_PORTS; i++) { 766*78549b94SAdrian Chadd 767dd846bddSAdrian Chadd /* set pvid = 1; there's only one vlangroup */ 768dd846bddSAdrian Chadd t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S; 769dd846bddSAdrian Chadd t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S; 7707330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN0(i), t); 7717330dd0bSAdrian Chadd 7727330dd0bSAdrian Chadd /* set egress == out_keep */ 7737330dd0bSAdrian Chadd mode = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH; 7747330dd0bSAdrian Chadd 7757330dd0bSAdrian Chadd t = AR8327_PORT_VLAN1_PORT_VLAN_PROP; 7767330dd0bSAdrian Chadd t |= mode << AR8327_PORT_VLAN1_OUT_MODE_S; 7777330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN1(i), t); 7787330dd0bSAdrian Chadd 779dd846bddSAdrian Chadd /* Ports can see other ports */ 780*78549b94SAdrian Chadd t = (ports & ~(1 << i)); /* all ports besides us */ 7817330dd0bSAdrian Chadd t |= AR8327_PORT_LOOKUP_LEARN; 7827330dd0bSAdrian Chadd 7837330dd0bSAdrian Chadd /* in_port_only, forward */ 7847330dd0bSAdrian Chadd t |= AR8X16_PORT_VLAN_MODE_PORT_ONLY << AR8327_PORT_LOOKUP_IN_MODE_S; 7857330dd0bSAdrian Chadd t |= AR8X16_PORT_CTRL_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; 7867330dd0bSAdrian Chadd arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(i), t); 78703b5d827SAdrian Chadd 78803b5d827SAdrian Chadd /* 78903b5d827SAdrian Chadd * Disable port mirroring entirely. 79003b5d827SAdrian Chadd */ 79103b5d827SAdrian Chadd arswitch_modifyreg(sc->sc_dev, 79203b5d827SAdrian Chadd AR8327_REG_PORT_LOOKUP(i), 79303b5d827SAdrian Chadd AR8327_PORT_LOOKUP_ING_MIRROR_EN, 79403b5d827SAdrian Chadd 0); 79503b5d827SAdrian Chadd arswitch_modifyreg(sc->sc_dev, 79603b5d827SAdrian Chadd AR8327_REG_PORT_HOL_CTRL1(i), 79703b5d827SAdrian Chadd AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN, 79803b5d827SAdrian Chadd 0); 7997330dd0bSAdrian Chadd } 800*78549b94SAdrian Chadd 801*78549b94SAdrian Chadd ARSWITCH_UNLOCK(sc); 8027330dd0bSAdrian Chadd } 8037330dd0bSAdrian Chadd 8047330dd0bSAdrian Chadd static int 8057330dd0bSAdrian Chadd ar8327_vlan_getvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg) 8067330dd0bSAdrian Chadd { 807*78549b94SAdrian Chadd 808*78549b94SAdrian Chadd #if 0 809*78549b94SAdrian Chadd /* XXX for now, no dot1q vlans */ 810*78549b94SAdrian Chadd if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) 811*78549b94SAdrian Chadd return (EINVAL); 812*78549b94SAdrian Chadd return (ar8xxx_getvgroup(sc, vg)); 813*78549b94SAdrian Chadd #endif 8147330dd0bSAdrian Chadd return (0); 8157330dd0bSAdrian Chadd } 8167330dd0bSAdrian Chadd 8177330dd0bSAdrian Chadd static int 8187330dd0bSAdrian Chadd ar8327_vlan_setvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg) 8197330dd0bSAdrian Chadd { 8207330dd0bSAdrian Chadd 821*78549b94SAdrian Chadd #if 0 822*78549b94SAdrian Chadd /* XXX for now, no dot1q vlans */ 823*78549b94SAdrian Chadd if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) 824*78549b94SAdrian Chadd return (EINVAL); 825*78549b94SAdrian Chadd return (ar8xxx_setvgroup(sc, vg)); 826*78549b94SAdrian Chadd #endif 8277330dd0bSAdrian Chadd return (0); 8287330dd0bSAdrian Chadd } 8297330dd0bSAdrian Chadd 8307330dd0bSAdrian Chadd static int 8317330dd0bSAdrian Chadd ar8327_get_pvid(struct arswitch_softc *sc, int port, int *pvid) 8327330dd0bSAdrian Chadd { 8337330dd0bSAdrian Chadd 8347330dd0bSAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 8357330dd0bSAdrian Chadd return (0); 8367330dd0bSAdrian Chadd } 8377330dd0bSAdrian Chadd 8387330dd0bSAdrian Chadd static int 8397330dd0bSAdrian Chadd ar8327_set_pvid(struct arswitch_softc *sc, int port, int pvid) 8407330dd0bSAdrian Chadd { 8417330dd0bSAdrian Chadd 8427330dd0bSAdrian Chadd device_printf(sc->sc_dev, "%s: called\n", __func__); 8437330dd0bSAdrian Chadd return (0); 8447330dd0bSAdrian Chadd } 8457330dd0bSAdrian Chadd 8464ff2f60dSAdrian Chadd static int 8474ff2f60dSAdrian Chadd ar8327_atu_flush(struct arswitch_softc *sc) 8484ff2f60dSAdrian Chadd { 8494ff2f60dSAdrian Chadd 8504ff2f60dSAdrian Chadd int ret; 8514ff2f60dSAdrian Chadd 8524ff2f60dSAdrian Chadd ret = arswitch_waitreg(sc->sc_dev, 8534ff2f60dSAdrian Chadd AR8327_REG_ATU_FUNC, 8544ff2f60dSAdrian Chadd AR8327_ATU_FUNC_BUSY, 8554ff2f60dSAdrian Chadd 0, 8564ff2f60dSAdrian Chadd 1000); 8574ff2f60dSAdrian Chadd 8584ff2f60dSAdrian Chadd if (ret) 8594ff2f60dSAdrian Chadd device_printf(sc->sc_dev, "%s: waitreg failed\n", __func__); 8604ff2f60dSAdrian Chadd 8614ff2f60dSAdrian Chadd if (!ret) 8624ff2f60dSAdrian Chadd arswitch_writereg(sc->sc_dev, 8634ff2f60dSAdrian Chadd AR8327_REG_ATU_FUNC, 8644ff2f60dSAdrian Chadd AR8327_ATU_FUNC_OP_FLUSH); 8654ff2f60dSAdrian Chadd return (ret); 8664ff2f60dSAdrian Chadd } 8674ff2f60dSAdrian Chadd 8687330dd0bSAdrian Chadd void 8697330dd0bSAdrian Chadd ar8327_attach(struct arswitch_softc *sc) 8707330dd0bSAdrian Chadd { 8717330dd0bSAdrian Chadd 8727330dd0bSAdrian Chadd sc->hal.arswitch_hw_setup = ar8327_hw_setup; 8737330dd0bSAdrian Chadd sc->hal.arswitch_hw_global_setup = ar8327_hw_global_setup; 8747330dd0bSAdrian Chadd 8757330dd0bSAdrian Chadd sc->hal.arswitch_port_init = ar8327_port_init; 876*78549b94SAdrian Chadd 877*78549b94SAdrian Chadd sc->hal.arswitch_vlan_getvgroup = ar8327_vlan_getvgroup; 878*78549b94SAdrian Chadd sc->hal.arswitch_vlan_setvgroup = ar8327_vlan_setvgroup; 8797330dd0bSAdrian Chadd sc->hal.arswitch_port_vlan_setup = ar8327_port_vlan_setup; 8807330dd0bSAdrian Chadd sc->hal.arswitch_port_vlan_get = ar8327_port_vlan_get; 8817330dd0bSAdrian Chadd 8827330dd0bSAdrian Chadd sc->hal.arswitch_vlan_init_hw = ar8327_reset_vlans; 8837330dd0bSAdrian Chadd sc->hal.arswitch_vlan_get_pvid = ar8327_get_pvid; 8847330dd0bSAdrian Chadd sc->hal.arswitch_vlan_set_pvid = ar8327_set_pvid; 8857330dd0bSAdrian Chadd 8864ff2f60dSAdrian Chadd sc->hal.arswitch_atu_flush = ar8327_atu_flush; 8874ff2f60dSAdrian Chadd 888*78549b94SAdrian Chadd /* 889*78549b94SAdrian Chadd * Reading the PHY via the MDIO interface currently doesn't 890*78549b94SAdrian Chadd * work correctly. 891*78549b94SAdrian Chadd * 892*78549b94SAdrian Chadd * So for now, just go direct to the PHY registers themselves. 893*78549b94SAdrian Chadd * This has always worked on external devices, but not internal 894*78549b94SAdrian Chadd * devices (AR934x, AR724x, AR933x.) 895*78549b94SAdrian Chadd */ 896*78549b94SAdrian Chadd sc->hal.arswitch_phy_read = arswitch_readphy_external; 897*78549b94SAdrian Chadd sc->hal.arswitch_phy_write = arswitch_writephy_external; 898*78549b94SAdrian Chadd 8997330dd0bSAdrian Chadd /* Set the switch vlan capabilities. */ 9007330dd0bSAdrian Chadd sc->info.es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q | 9017330dd0bSAdrian Chadd ETHERSWITCH_VLAN_PORT | ETHERSWITCH_VLAN_DOUBLE_TAG; 9027330dd0bSAdrian Chadd sc->info.es_nvlangroups = AR8X16_MAX_VLANS; 9037330dd0bSAdrian Chadd } 904