xref: /freebsd/sys/dev/etherswitch/arswitch/arswitch_8327.c (revision 749cac133fda68618915a4cceaff22cc9871ad60)
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>
6078549b94SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_phy.h>
6178549b94SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_vlans.h>
6278549b94SAdrian 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 
29678549b94SAdrian 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)) {
56878549b94SAdrian 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 */
658*749cac13SAdrian Chadd 	/* GMAC0 (CPU), GMAC1..5 (PHYs), GMAC6 (CPU) */
659*749cac13SAdrian Chadd 	sc->info.es_nports = 7;
6604ff2f60dSAdrian Chadd 
6617330dd0bSAdrian Chadd 	return (0);
6627330dd0bSAdrian Chadd }
6637330dd0bSAdrian Chadd 
6647330dd0bSAdrian Chadd /*
66578549b94SAdrian Chadd  * Port setup.  Called at attach time.
6667330dd0bSAdrian Chadd  */
6677330dd0bSAdrian Chadd static void
6687330dd0bSAdrian Chadd ar8327_port_init(struct arswitch_softc *sc, int port)
6697330dd0bSAdrian Chadd {
6707330dd0bSAdrian Chadd 	uint32_t t;
67178549b94SAdrian Chadd 	int ports;
67278549b94SAdrian Chadd 
67378549b94SAdrian Chadd 	/* For now, port can see all other ports */
67478549b94SAdrian Chadd 	ports = 0x7f;
6757330dd0bSAdrian Chadd 
6769ab21e32SAdrian Chadd 	if (port == AR8X16_PORT_CPU)
6779ab21e32SAdrian Chadd 		t = sc->ar8327.port0_status;
6787330dd0bSAdrian Chadd 	else if (port == 6)
6799ab21e32SAdrian Chadd 		t = sc->ar8327.port6_status;
6807330dd0bSAdrian Chadd         else
6817330dd0bSAdrian Chadd 		t = AR8X16_PORT_STS_LINK_AUTO;
6827330dd0bSAdrian Chadd 
6837330dd0bSAdrian Chadd 	arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_STATUS(port), t);
6847330dd0bSAdrian Chadd 	arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_HEADER(port), 0);
6857330dd0bSAdrian Chadd 
6860d2041a0SAdrian Chadd 	/*
6870d2041a0SAdrian Chadd 	 * Default to 1 port group.
6880d2041a0SAdrian Chadd 	 */
6897330dd0bSAdrian Chadd 	t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S;
6907330dd0bSAdrian Chadd 	t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S;
6917330dd0bSAdrian Chadd 	arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN0(port), t);
6927330dd0bSAdrian Chadd 
6937330dd0bSAdrian Chadd 	t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S;
6947330dd0bSAdrian Chadd 	arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN1(port), t);
6957330dd0bSAdrian Chadd 
69603b5d827SAdrian Chadd 	/*
69703b5d827SAdrian Chadd 	 * This doesn't configure any ports which this port can "see".
69803b5d827SAdrian Chadd 	 * bits 0-6 control which ports a frame coming into this port
69903b5d827SAdrian Chadd 	 * can be sent out to.
70003b5d827SAdrian Chadd 	 *
70103b5d827SAdrian Chadd 	 * So by doing this, we're making it impossible to send frames out
70203b5d827SAdrian Chadd 	 * to that port.
70303b5d827SAdrian Chadd 	 */
7047330dd0bSAdrian Chadd 	t = AR8327_PORT_LOOKUP_LEARN;
7057330dd0bSAdrian Chadd 	t |= AR8X16_PORT_CTRL_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S;
70603b5d827SAdrian Chadd 
70703b5d827SAdrian Chadd 	/* So this allows traffic to any port except ourselves */
70878549b94SAdrian Chadd 	t |= (ports & ~(1 << port));
7097330dd0bSAdrian Chadd 	arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(port), t);
7107330dd0bSAdrian Chadd }
7117330dd0bSAdrian Chadd 
7127330dd0bSAdrian Chadd static int
7137330dd0bSAdrian Chadd ar8327_port_vlan_setup(struct arswitch_softc *sc, etherswitch_port_t *p)
7147330dd0bSAdrian Chadd {
7157330dd0bSAdrian Chadd 
716*749cac13SAdrian Chadd 	/* Check: ADDTAG/STRIPTAG - exclusive */
717*749cac13SAdrian Chadd 
718*749cac13SAdrian Chadd 	ARSWITCH_LOCK(sc);
719*749cac13SAdrian Chadd 
720*749cac13SAdrian Chadd 	/* Set the PVID. */
721*749cac13SAdrian Chadd 	if (p->es_pvid != 0)
722*749cac13SAdrian Chadd 		sc->hal.arswitch_vlan_set_pvid(sc, p->es_port, p->es_pvid);
723*749cac13SAdrian Chadd 
724*749cac13SAdrian Chadd 	/*
725*749cac13SAdrian Chadd 	 * DOUBLE_TAG
726*749cac13SAdrian Chadd 	 * VLAN_MODE_ADD
727*749cac13SAdrian Chadd 	 * VLAN_MODE_STRIP
728*749cac13SAdrian Chadd 	 */
729*749cac13SAdrian Chadd 	ARSWITCH_UNLOCK(sc);
7307330dd0bSAdrian Chadd 	return (0);
7317330dd0bSAdrian Chadd }
7327330dd0bSAdrian Chadd 
73378549b94SAdrian Chadd /*
73478549b94SAdrian Chadd  * Get the port VLAN configuration.
73578549b94SAdrian Chadd  */
7367330dd0bSAdrian Chadd static int
7377330dd0bSAdrian Chadd ar8327_port_vlan_get(struct arswitch_softc *sc, etherswitch_port_t *p)
7387330dd0bSAdrian Chadd {
739*749cac13SAdrian Chadd 
740*749cac13SAdrian Chadd 	ARSWITCH_LOCK(sc);
741*749cac13SAdrian Chadd 
742*749cac13SAdrian Chadd 	/* Retrieve the PVID */
743*749cac13SAdrian Chadd 	sc->hal.arswitch_vlan_get_pvid(sc, p->es_port, &p->es_pvid);
744*749cac13SAdrian Chadd 
745*749cac13SAdrian Chadd 	/* Retrieve the current port configuration */
746*749cac13SAdrian Chadd 	/*
747*749cac13SAdrian Chadd 	 * DOUBLE_TAG
748*749cac13SAdrian Chadd 	 * VLAN_MODE_ADD
749*749cac13SAdrian Chadd 	 * VLAN_MODE_STRIP
750*749cac13SAdrian Chadd 	 */
751*749cac13SAdrian Chadd 
752*749cac13SAdrian Chadd 	ARSWITCH_UNLOCK(sc);
7537330dd0bSAdrian Chadd 	return (0);
7547330dd0bSAdrian Chadd }
7557330dd0bSAdrian Chadd 
7567330dd0bSAdrian Chadd static void
7577330dd0bSAdrian Chadd ar8327_reset_vlans(struct arswitch_softc *sc)
7587330dd0bSAdrian Chadd {
7597330dd0bSAdrian Chadd 	int i;
7607330dd0bSAdrian Chadd 	uint32_t mode, t;
76178549b94SAdrian Chadd 	int ports;
76278549b94SAdrian Chadd 
76378549b94SAdrian Chadd 	ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
76478549b94SAdrian Chadd 	ARSWITCH_LOCK(sc);
76578549b94SAdrian Chadd 
76678549b94SAdrian Chadd 	/* Clear the existing VLAN configuration */
76778549b94SAdrian Chadd 	memset(sc->vid, 0, sizeof(sc->vid));
7687330dd0bSAdrian Chadd 
7697330dd0bSAdrian Chadd 	/*
77003b5d827SAdrian Chadd 	 * Disable mirroring.
77103b5d827SAdrian Chadd 	 */
77203b5d827SAdrian Chadd 	arswitch_modifyreg(sc->sc_dev, AR8327_REG_FWD_CTRL0,
77303b5d827SAdrian Chadd 	    AR8327_FWD_CTRL0_MIRROR_PORT,
77403b5d827SAdrian Chadd 	    (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S));
77503b5d827SAdrian Chadd 
77603b5d827SAdrian Chadd 	/*
77778549b94SAdrian Chadd 	 * XXX TODO: disable any Q-in-Q port configuration,
77878549b94SAdrian Chadd 	 * tagging, egress filters, etc.
7797330dd0bSAdrian Chadd 	 */
78078549b94SAdrian Chadd 
78178549b94SAdrian Chadd 	/*
78278549b94SAdrian Chadd 	 * For now, let's default to one portgroup, just so traffic
78378549b94SAdrian Chadd 	 * flows.  All ports can see other ports. There are two CPU GMACs
78478549b94SAdrian Chadd 	 * (GMAC0, GMAC6), GMAC1..GMAC5 are external PHYs.
78578549b94SAdrian Chadd 	 *
78678549b94SAdrian Chadd 	 * (ETHERSWITCH_VLAN_PORT)
78778549b94SAdrian Chadd 	 */
78878549b94SAdrian Chadd 	ports = 0x7f;
78978549b94SAdrian Chadd 
7907330dd0bSAdrian Chadd 	for (i = 0; i < AR8327_NUM_PORTS; i++) {
79178549b94SAdrian Chadd 
792*749cac13SAdrian Chadd 		if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT)
793*749cac13SAdrian Chadd 			sc->vid[i] = i | ETHERSWITCH_VID_VALID;
794*749cac13SAdrian Chadd 
795*749cac13SAdrian Chadd 		/* set pvid = 1; there's only one vlangroup to start with */
796dd846bddSAdrian Chadd 		t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S;
797dd846bddSAdrian Chadd 		t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S;
7987330dd0bSAdrian Chadd 		arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN0(i), t);
7997330dd0bSAdrian Chadd 
8007330dd0bSAdrian Chadd 		/* set egress == out_keep */
8017330dd0bSAdrian Chadd 		mode = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH;
8027330dd0bSAdrian Chadd 
8037330dd0bSAdrian Chadd 		t = AR8327_PORT_VLAN1_PORT_VLAN_PROP;
8047330dd0bSAdrian Chadd 		t |= mode << AR8327_PORT_VLAN1_OUT_MODE_S;
8057330dd0bSAdrian Chadd 		arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN1(i), t);
8067330dd0bSAdrian Chadd 
807dd846bddSAdrian Chadd 		/* Ports can see other ports */
80878549b94SAdrian Chadd 		t = (ports & ~(1 << i));	/* all ports besides us */
8097330dd0bSAdrian Chadd 		t |= AR8327_PORT_LOOKUP_LEARN;
8107330dd0bSAdrian Chadd 
8117330dd0bSAdrian Chadd 		/* in_port_only, forward */
8127330dd0bSAdrian Chadd 		t |= AR8X16_PORT_VLAN_MODE_PORT_ONLY << AR8327_PORT_LOOKUP_IN_MODE_S;
8137330dd0bSAdrian Chadd 		t |= AR8X16_PORT_CTRL_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S;
8147330dd0bSAdrian Chadd 		arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(i), t);
81503b5d827SAdrian Chadd 
81603b5d827SAdrian Chadd 		/*
81703b5d827SAdrian Chadd 		 * Disable port mirroring entirely.
81803b5d827SAdrian Chadd 		 */
81903b5d827SAdrian Chadd 		arswitch_modifyreg(sc->sc_dev,
82003b5d827SAdrian Chadd 		    AR8327_REG_PORT_LOOKUP(i),
82103b5d827SAdrian Chadd 		    AR8327_PORT_LOOKUP_ING_MIRROR_EN,
82203b5d827SAdrian Chadd 		    0);
82303b5d827SAdrian Chadd 		arswitch_modifyreg(sc->sc_dev,
82403b5d827SAdrian Chadd 		    AR8327_REG_PORT_HOL_CTRL1(i),
82503b5d827SAdrian Chadd 		    AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN,
82603b5d827SAdrian Chadd 		    0);
8277330dd0bSAdrian Chadd 	}
82878549b94SAdrian Chadd 
82978549b94SAdrian Chadd 	ARSWITCH_UNLOCK(sc);
8307330dd0bSAdrian Chadd }
8317330dd0bSAdrian Chadd 
8327330dd0bSAdrian Chadd static int
833*749cac13SAdrian Chadd ar8327_vlan_get_port(struct arswitch_softc *sc, uint32_t *ports, int vid)
834*749cac13SAdrian Chadd {
835*749cac13SAdrian Chadd 	int port;
836*749cac13SAdrian Chadd 	uint32_t reg;
837*749cac13SAdrian Chadd 
838*749cac13SAdrian Chadd 	ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
839*749cac13SAdrian Chadd 
840*749cac13SAdrian Chadd 	/* For port based vlans the vlanid is the same as the port index. */
841*749cac13SAdrian Chadd 	port = vid & ETHERSWITCH_VID_MASK;
842*749cac13SAdrian Chadd 	reg = arswitch_readreg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(port));
843*749cac13SAdrian Chadd 	*ports = reg & 0x7f;
844*749cac13SAdrian Chadd 	return (0);
845*749cac13SAdrian Chadd }
846*749cac13SAdrian Chadd 
847*749cac13SAdrian Chadd static int
848*749cac13SAdrian Chadd ar8327_vlan_set_port(struct arswitch_softc *sc, uint32_t ports, int vid)
849*749cac13SAdrian Chadd {
850*749cac13SAdrian Chadd 	int err, port;
851*749cac13SAdrian Chadd 
852*749cac13SAdrian Chadd 	ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
853*749cac13SAdrian Chadd 
854*749cac13SAdrian Chadd 	/* For port based vlans the vlanid is the same as the port index. */
855*749cac13SAdrian Chadd 	port = vid & ETHERSWITCH_VID_MASK;
856*749cac13SAdrian Chadd 
857*749cac13SAdrian Chadd 	err = arswitch_modifyreg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(port),
858*749cac13SAdrian Chadd 	    0x7f, /* vlan membership mask */
859*749cac13SAdrian Chadd 	    (ports & 0x7f));
860*749cac13SAdrian Chadd 
861*749cac13SAdrian Chadd 	if (err)
862*749cac13SAdrian Chadd 		return (err);
863*749cac13SAdrian Chadd 	return (0);
864*749cac13SAdrian Chadd }
865*749cac13SAdrian Chadd 
866*749cac13SAdrian Chadd static int
8677330dd0bSAdrian Chadd ar8327_vlan_getvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg)
8687330dd0bSAdrian Chadd {
86978549b94SAdrian Chadd 
87078549b94SAdrian Chadd 	/* XXX for now, no dot1q vlans */
87178549b94SAdrian Chadd 	if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q)
87278549b94SAdrian Chadd 		return (EINVAL);
87378549b94SAdrian Chadd 	return (ar8xxx_getvgroup(sc, vg));
8747330dd0bSAdrian Chadd }
8757330dd0bSAdrian Chadd 
8767330dd0bSAdrian Chadd static int
8777330dd0bSAdrian Chadd ar8327_vlan_setvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg)
8787330dd0bSAdrian Chadd {
8797330dd0bSAdrian Chadd 
88078549b94SAdrian Chadd 	/* XXX for now, no dot1q vlans */
88178549b94SAdrian Chadd 	if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q)
88278549b94SAdrian Chadd 		return (EINVAL);
88378549b94SAdrian Chadd 	return (ar8xxx_setvgroup(sc, vg));
8847330dd0bSAdrian Chadd }
8857330dd0bSAdrian Chadd 
8867330dd0bSAdrian Chadd static int
8877330dd0bSAdrian Chadd ar8327_get_pvid(struct arswitch_softc *sc, int port, int *pvid)
8887330dd0bSAdrian Chadd {
889*749cac13SAdrian Chadd 	uint32_t reg;
8907330dd0bSAdrian Chadd 
891*749cac13SAdrian Chadd 	ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
892*749cac13SAdrian Chadd 
893*749cac13SAdrian Chadd 	/*
894*749cac13SAdrian Chadd 	 * XXX for now, assuming it's CVID; likely very wrong!
895*749cac13SAdrian Chadd 	 */
896*749cac13SAdrian Chadd 	port = port & ETHERSWITCH_VID_MASK;
897*749cac13SAdrian Chadd 	reg = arswitch_readreg(sc->sc_dev, AR8327_REG_PORT_VLAN0(port));
898*749cac13SAdrian Chadd 	reg = reg >> AR8327_PORT_VLAN0_DEF_CVID_S;
899*749cac13SAdrian Chadd 	reg = reg & 0xfff;
900*749cac13SAdrian Chadd 
901*749cac13SAdrian Chadd 	*pvid = reg;
9027330dd0bSAdrian Chadd 	return (0);
9037330dd0bSAdrian Chadd }
9047330dd0bSAdrian Chadd 
9057330dd0bSAdrian Chadd static int
9067330dd0bSAdrian Chadd ar8327_set_pvid(struct arswitch_softc *sc, int port, int pvid)
9077330dd0bSAdrian Chadd {
908*749cac13SAdrian Chadd 	uint32_t t;
9097330dd0bSAdrian Chadd 
910*749cac13SAdrian Chadd 	/* Limit pvid to valid values */
911*749cac13SAdrian Chadd 	pvid &= 0x7f;
912*749cac13SAdrian Chadd 
913*749cac13SAdrian Chadd 	t = pvid << AR8327_PORT_VLAN0_DEF_SVID_S;
914*749cac13SAdrian Chadd 	t |= pvid << AR8327_PORT_VLAN0_DEF_CVID_S;
915*749cac13SAdrian Chadd 	arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN0(port), t);
916*749cac13SAdrian Chadd 
9177330dd0bSAdrian Chadd 	return (0);
9187330dd0bSAdrian Chadd }
9197330dd0bSAdrian Chadd 
9204ff2f60dSAdrian Chadd static int
9214ff2f60dSAdrian Chadd ar8327_atu_flush(struct arswitch_softc *sc)
9224ff2f60dSAdrian Chadd {
9234ff2f60dSAdrian Chadd 
9244ff2f60dSAdrian Chadd 	int ret;
9254ff2f60dSAdrian Chadd 
9264ff2f60dSAdrian Chadd 	ret = arswitch_waitreg(sc->sc_dev,
9274ff2f60dSAdrian Chadd 	    AR8327_REG_ATU_FUNC,
9284ff2f60dSAdrian Chadd 	    AR8327_ATU_FUNC_BUSY,
9294ff2f60dSAdrian Chadd 	    0,
9304ff2f60dSAdrian Chadd 	    1000);
9314ff2f60dSAdrian Chadd 
9324ff2f60dSAdrian Chadd 	if (ret)
9334ff2f60dSAdrian Chadd 		device_printf(sc->sc_dev, "%s: waitreg failed\n", __func__);
9344ff2f60dSAdrian Chadd 
9354ff2f60dSAdrian Chadd 	if (!ret)
9364ff2f60dSAdrian Chadd 		arswitch_writereg(sc->sc_dev,
9374ff2f60dSAdrian Chadd 		    AR8327_REG_ATU_FUNC,
9384ff2f60dSAdrian Chadd 		    AR8327_ATU_FUNC_OP_FLUSH);
9394ff2f60dSAdrian Chadd 	return (ret);
9404ff2f60dSAdrian Chadd }
9414ff2f60dSAdrian Chadd 
9427330dd0bSAdrian Chadd void
9437330dd0bSAdrian Chadd ar8327_attach(struct arswitch_softc *sc)
9447330dd0bSAdrian Chadd {
9457330dd0bSAdrian Chadd 
9467330dd0bSAdrian Chadd 	sc->hal.arswitch_hw_setup = ar8327_hw_setup;
9477330dd0bSAdrian Chadd 	sc->hal.arswitch_hw_global_setup = ar8327_hw_global_setup;
9487330dd0bSAdrian Chadd 
9497330dd0bSAdrian Chadd 	sc->hal.arswitch_port_init = ar8327_port_init;
95078549b94SAdrian Chadd 
95178549b94SAdrian Chadd 	sc->hal.arswitch_vlan_getvgroup = ar8327_vlan_getvgroup;
95278549b94SAdrian Chadd 	sc->hal.arswitch_vlan_setvgroup = ar8327_vlan_setvgroup;
9537330dd0bSAdrian Chadd 	sc->hal.arswitch_port_vlan_setup = ar8327_port_vlan_setup;
9547330dd0bSAdrian Chadd 	sc->hal.arswitch_port_vlan_get = ar8327_port_vlan_get;
9557330dd0bSAdrian Chadd 
9567330dd0bSAdrian Chadd 	sc->hal.arswitch_vlan_init_hw = ar8327_reset_vlans;
9577330dd0bSAdrian Chadd 	sc->hal.arswitch_vlan_get_pvid = ar8327_get_pvid;
9587330dd0bSAdrian Chadd 	sc->hal.arswitch_vlan_set_pvid = ar8327_set_pvid;
9597330dd0bSAdrian Chadd 
960*749cac13SAdrian Chadd 	sc->hal.arswitch_get_port_vlan = ar8327_vlan_get_port;
961*749cac13SAdrian Chadd 	sc->hal.arswitch_set_port_vlan = ar8327_vlan_set_port;
962*749cac13SAdrian Chadd 
9634ff2f60dSAdrian Chadd 	sc->hal.arswitch_atu_flush = ar8327_atu_flush;
9644ff2f60dSAdrian Chadd 
96578549b94SAdrian Chadd 	/*
96678549b94SAdrian Chadd 	 * Reading the PHY via the MDIO interface currently doesn't
96778549b94SAdrian Chadd 	 * work correctly.
96878549b94SAdrian Chadd 	 *
96978549b94SAdrian Chadd 	 * So for now, just go direct to the PHY registers themselves.
97078549b94SAdrian Chadd 	 * This has always worked  on external devices, but not internal
97178549b94SAdrian Chadd 	 * devices (AR934x, AR724x, AR933x.)
97278549b94SAdrian Chadd 	 */
97378549b94SAdrian Chadd 	sc->hal.arswitch_phy_read = arswitch_readphy_external;
97478549b94SAdrian Chadd 	sc->hal.arswitch_phy_write = arswitch_writephy_external;
97578549b94SAdrian Chadd 
9767330dd0bSAdrian Chadd 	/* Set the switch vlan capabilities. */
9777330dd0bSAdrian Chadd 	sc->info.es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q |
9787330dd0bSAdrian Chadd 	    ETHERSWITCH_VLAN_PORT | ETHERSWITCH_VLAN_DOUBLE_TAG;
9797330dd0bSAdrian Chadd 	sc->info.es_nvlangroups = AR8X16_MAX_VLANS;
9807330dd0bSAdrian Chadd }
981