int arswitch_writephy(device_t dev, int phy, int reg, int data) { uint32_t ctrl; int err, timeout; if (reg < 0 || reg >= 32) return (ENXIO); err = arswitch_writereg_lsb(dev, AR8X16_REG_MDIO_CTRL, (data & AR8X16_MDIO_CTRL_DATA_MASK)); DEVERR(dev, err, "arswitch_writephy()=%d: phy=%d.%02x\n", phy, reg); if (err != 0) return (err); err = arswitch_writereg_msb(dev, AR8X16_REG_MDIO_CTRL, AR8X16_MDIO_CTRL_BUSY | AR8X16_MDIO_CTRL_MASTER_EN | AR8X16_MDIO_CTRL_CMD_WRITE | (phy << AR8X16_MDIO_CTRL_PHY_ADDR_SHIFT) | (reg << AR8X16_MDIO_CTRL_REG_ADDR_SHIFT)); DEVERR(dev, err, "arswitch_writephy()=%d: phy=%d.%02x\n", phy, reg); if (err != 0) return (err); for (timeout = 100; timeout--; ) { ctrl = arswitch_readreg(dev, AR8X16_REG_MDIO_CTRL); if ((ctrl & AR8X16_MDIO_CTRL_BUSY) == 0) break; } if (timeout < 0) err = EIO; DEVERR(dev, err, "arswitch_writephy()=%d: phy=%d.%02x\n", phy, reg); return (err); }
int arswitch_writephy(device_t dev, int phy, int reg, int data) { struct arswitch_softc *sc; uint32_t ctrl; int err, timeout; sc = device_get_softc(dev); ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); if (reg < 0 || reg >= 32) return (ENXIO); ARSWITCH_LOCK(sc); err = arswitch_writereg(dev, AR8X16_REG_MDIO_CTRL, AR8X16_MDIO_CTRL_BUSY | AR8X16_MDIO_CTRL_MASTER_EN | AR8X16_MDIO_CTRL_CMD_WRITE | (phy << AR8X16_MDIO_CTRL_PHY_ADDR_SHIFT) | (reg << AR8X16_MDIO_CTRL_REG_ADDR_SHIFT) | (data & AR8X16_MDIO_CTRL_DATA_MASK)); if (err != 0) goto out; for (timeout = 100; timeout--; ) { ctrl = arswitch_readreg(dev, AR8X16_REG_MDIO_CTRL); if ((ctrl & AR8X16_MDIO_CTRL_BUSY) == 0) break; } if (timeout < 0) err = EIO; out: DEVERR(dev, err, "arswitch_writephy()=%d: phy=%d.%02x\n", phy, reg); ARSWITCH_UNLOCK(sc); return (err); }
static int ar8327_vlan_get_port(struct arswitch_softc *sc, uint32_t *ports, int vid) { int port; uint32_t reg; ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); /* For port based vlans the vlanid is the same as the port index. */ port = vid & ETHERSWITCH_VID_MASK; reg = arswitch_readreg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(port)); *ports = reg & 0x7f; return (0); }
int arswitch_writephy_internal(device_t dev, int phy, int reg, int data) { struct arswitch_softc *sc; uint32_t ctrl; int err, timeout; uint32_t a; sc = device_get_softc(dev); ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); if (reg < 0 || reg >= 32) return (ENXIO); if (AR8X16_IS_SWITCH(sc, AR8327)) a = AR8327_REG_MDIO_CTRL; else a = AR8X16_REG_MDIO_CTRL; ARSWITCH_LOCK(sc); err = arswitch_writereg(dev, a, AR8X16_MDIO_CTRL_BUSY | AR8X16_MDIO_CTRL_MASTER_EN | AR8X16_MDIO_CTRL_CMD_WRITE | (phy << AR8X16_MDIO_CTRL_PHY_ADDR_SHIFT) | (reg << AR8X16_MDIO_CTRL_REG_ADDR_SHIFT) | (data & AR8X16_MDIO_CTRL_DATA_MASK)); if (err != 0) goto out; for (timeout = 100; timeout--; ) { ctrl = arswitch_readreg(dev, a); if ((ctrl & AR8X16_MDIO_CTRL_BUSY) == 0) break; } if (timeout < 0) err = EIO; DPRINTF(sc, ARSWITCH_DBG_PHYIO, "%s: phy=0x%08x, reg=0x%08x, data=0x%08x, err=%d\n", __func__, phy, reg, data, err); out: DEVERR(dev, err, "arswitch_writephy()=%d: phy=%d.%02x\n", phy, reg); ARSWITCH_UNLOCK(sc); return (err); }
static int ar8327_get_pvid(struct arswitch_softc *sc, int port, int *pvid) { uint32_t reg; ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); /* * XXX for now, assuming it's CVID; likely very wrong! */ port = port & ETHERSWITCH_VID_MASK; reg = arswitch_readreg(sc->sc_dev, AR8327_REG_PORT_VLAN0(port)); reg = reg >> AR8327_PORT_VLAN0_DEF_CVID_S; reg = reg & 0xfff; *pvid = reg; return (0); }
/* * Initialise other global values, for the AR8327. */ static int ar8327_hw_global_setup(struct arswitch_softc *sc) { uint32_t t; /* enable CPU port and disable mirror port */ t = AR8327_FWD_CTRL0_CPU_PORT_EN | AR8327_FWD_CTRL0_MIRROR_PORT; arswitch_writereg(sc->sc_dev, AR8327_REG_FWD_CTRL0, t); /* forward multicast and broadcast frames to CPU */ t = (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_UC_FLOOD_S) | (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_MC_FLOOD_S) | (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_BC_FLOOD_S); arswitch_writereg(sc->sc_dev, AR8327_REG_FWD_CTRL1, t); /* enable jumbo frames */ /* XXX need to macro-shift the value! */ arswitch_modifyreg(sc->sc_dev, AR8327_REG_MAX_FRAME_SIZE, AR8327_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2); /* Enable MIB counters */ arswitch_modifyreg(sc->sc_dev, AR8327_REG_MODULE_EN, AR8327_MODULE_EN_MIB, AR8327_MODULE_EN_MIB); /* Disable EEE on all ports due to stability issues */ t = arswitch_readreg(sc->sc_dev, AR8327_REG_EEE_CTRL); t |= AR8327_EEE_CTRL_DISABLE_PHY(0) | AR8327_EEE_CTRL_DISABLE_PHY(1) | AR8327_EEE_CTRL_DISABLE_PHY(2) | AR8327_EEE_CTRL_DISABLE_PHY(3) | AR8327_EEE_CTRL_DISABLE_PHY(4); arswitch_writereg(sc->sc_dev, AR8327_REG_EEE_CTRL, t); /* Set the right number of ports */ /* GMAC0 (CPU), GMAC1..5 (PHYs), GMAC6 (CPU) */ sc->info.es_nports = 7; return (0); }
static int ar8327_get_dot1q_vlan(struct arswitch_softc *sc, uint32_t *ports, uint32_t *untagged_ports, int vid) { int i, r; uint32_t op, reg, val; op = AR8327_VTU_FUNC1_OP_GET_ONE; /* Filter out the vid flags; only grab the VLAN ID */ vid &= 0xfff; /* XXX TODO: the VTU here stores egress mode - keep, tag, untagged, none */ r = ar8327_vlan_op(sc, op, vid, 0); if (r != 0) { device_printf(sc->sc_dev, "%s: %d: op failed\n", __func__, vid); } reg = arswitch_readreg(sc->sc_dev, AR8327_REG_VTU_FUNC0); DPRINTF(sc->sc_dev, "%s: %d: reg=0x%08x\n", __func__, vid, reg); /* * If any of the bits are set, update the port mask. * Worry about the port config itself when getport() is called. */ *ports = 0; for (i = 0; i < AR8327_NUM_PORTS; i++) { val = reg >> AR8327_VTU_FUNC0_EG_MODE_S(i); val = val & 0x3; /* XXX KEEP (unmodified?) */ if (val == AR8327_VTU_FUNC0_EG_MODE_TAG) { *ports |= (1 << i); } else if (val == AR8327_VTU_FUNC0_EG_MODE_UNTAG) { *ports |= (1 << i); *untagged_ports |= (1 << i); } } return (0); }
/* * Initialise the ar8327 specific hardware features from * the hints provided in the boot environment. */ static int ar8327_init_pdata(struct arswitch_softc *sc) { struct ar8327_pad_cfg pc; struct ar8327_port_cfg port_cfg; struct ar8327_sgmii_cfg scfg; struct ar8327_led_cfg lcfg; uint32_t t, new_pos, pos; /* Port 0 */ bzero(&port_cfg, sizeof(port_cfg)); sc->ar8327.port0_status = 0; if (ar8327_fetch_pdata_port(sc, &port_cfg, 0)) sc->ar8327.port0_status = ar8327_get_port_init_status(&port_cfg); /* Port 6 */ bzero(&port_cfg, sizeof(port_cfg)); sc->ar8327.port6_status = 0; if (ar8327_fetch_pdata_port(sc, &port_cfg, 6)) sc->ar8327.port6_status = ar8327_get_port_init_status(&port_cfg); /* Pad 0 */ bzero(&pc, sizeof(pc)); t = 0; if (ar8327_fetch_pdata_pad(sc, &pc, 0)) t = ar8327_get_pad_cfg(&pc); #if 0 if (AR8X16_IS_SWITCH(sc, AR8337)) t |= AR8337_PAD_MAC06_EXCHANGE_EN; #endif arswitch_writereg(sc->sc_dev, AR8327_REG_PAD0_MODE, t); /* Pad 5 */ bzero(&pc, sizeof(pc)); t = 0; if (ar8327_fetch_pdata_pad(sc, &pc, 5)) t = ar8327_get_pad_cfg(&pc); arswitch_writereg(sc->sc_dev, AR8327_REG_PAD5_MODE, t); /* Pad 6 */ bzero(&pc, sizeof(pc)); t = 0; if (ar8327_fetch_pdata_pad(sc, &pc, 6)) t = ar8327_get_pad_cfg(&pc); arswitch_writereg(sc->sc_dev, AR8327_REG_PAD6_MODE, t); pos = arswitch_readreg(sc->sc_dev, AR8327_REG_POWER_ON_STRIP); new_pos = pos; /* XXX LED config */ bzero(&lcfg, sizeof(lcfg)); if (ar8327_fetch_pdata_led(sc, &lcfg)) { if (lcfg.open_drain) new_pos |= AR8327_POWER_ON_STRIP_LED_OPEN_EN; else new_pos &= ~AR8327_POWER_ON_STRIP_LED_OPEN_EN; arswitch_writereg(sc->sc_dev, AR8327_REG_LED_CTRL0, lcfg.led_ctrl0); arswitch_writereg(sc->sc_dev, AR8327_REG_LED_CTRL1, lcfg.led_ctrl1); arswitch_writereg(sc->sc_dev, AR8327_REG_LED_CTRL2, lcfg.led_ctrl2); arswitch_writereg(sc->sc_dev, AR8327_REG_LED_CTRL3, lcfg.led_ctrl3); if (new_pos != pos) new_pos |= AR8327_POWER_ON_STRIP_POWER_ON_SEL; } /* SGMII config */ bzero(&scfg, sizeof(scfg)); if (ar8327_fetch_pdata_sgmii(sc, &scfg)) { t = scfg.sgmii_ctrl; if (sc->chip_rev == 1) t |= AR8327_SGMII_CTRL_EN_PLL | AR8327_SGMII_CTRL_EN_RX | AR8327_SGMII_CTRL_EN_TX; else t &= ~(AR8327_SGMII_CTRL_EN_PLL | AR8327_SGMII_CTRL_EN_RX | AR8327_SGMII_CTRL_EN_TX); arswitch_writereg(sc->sc_dev, AR8327_REG_SGMII_CTRL, t); if (scfg.serdes_aen) new_pos &= ~AR8327_POWER_ON_STRIP_SERDES_AEN; else new_pos |= AR8327_POWER_ON_STRIP_SERDES_AEN; } arswitch_writereg(sc->sc_dev, AR8327_REG_POWER_ON_STRIP, new_pos); return (0); }