/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipinit */ static void bgmac_chip_init(struct bgmac *bgmac) { /* Clear any erroneously pending interrupts */ bgmac_write(bgmac, BGMAC_INT_STATUS, ~0); /* 1 interrupt per received frame */ bgmac_write(bgmac, BGMAC_INT_RECV_LAZY, 1 << BGMAC_IRL_FC_SHIFT); /* Enable 802.3x tx flow control (honor received PAUSE frames) */ bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_RPI, 0, true); bgmac_set_rx_mode(bgmac->net_dev); bgmac_write_mac_address(bgmac, bgmac->net_dev->dev_addr); if (bgmac->loopback) bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_ML, false); else bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_ML, 0, false); bgmac_write(bgmac, BGMAC_RXMAX_LENGTH, 32 + ETHER_MAX_LEN); bgmac_chip_intrs_on(bgmac); bgmac_enable(bgmac); }
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipinit */ static void bgmac_chip_init(struct bgmac *bgmac, bool full_init) { struct bgmac_dma_ring *ring; int i; /* 1 interrupt per received frame */ bgmac_write(bgmac, BGMAC_INT_RECV_LAZY, 1 << BGMAC_IRL_FC_SHIFT); /* Enable 802.3x tx flow control (honor received PAUSE frames) */ bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_RPI, 0, true); bgmac_set_rx_mode(bgmac->net_dev); bgmac_write_mac_address(bgmac, bgmac->net_dev->dev_addr); if (bgmac->loopback) bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_ML, false); else bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_ML, 0, false); bgmac_write(bgmac, BGMAC_RXMAX_LENGTH, 32 + ETHER_MAX_LEN); if (full_init) { bgmac_dma_init(bgmac); if (1) /* FIXME: is there any case we don't want IRQs? */ bgmac_chip_intrs_on(bgmac); } else { for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) { ring = &bgmac->rx_ring[i]; bgmac_dma_rx_enable(bgmac, ring); } } bgmac_enable(bgmac); }
static void bgmac_set_rx_mode(struct net_device *net_dev) { struct bgmac *bgmac = netdev_priv(net_dev); if (net_dev->flags & IFF_PROMISC) bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_PROM, true); else bgmac_cmdcfg_maskset(bgmac, ~BGMAC_CMDCFG_PROM, 0, true); }
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_speed */ static void bgmac_mac_speed(struct bgmac *bgmac) { u32 mask = ~(BGMAC_CMDCFG_ES_MASK | BGMAC_CMDCFG_HD); u32 set = 0; switch (bgmac->mac_speed) { case SPEED_10: set |= BGMAC_CMDCFG_ES_10; break; case SPEED_100: set |= BGMAC_CMDCFG_ES_100; break; case SPEED_1000: set |= BGMAC_CMDCFG_ES_1000; break; case SPEED_2500: set |= BGMAC_CMDCFG_ES_2500; break; default: bgmac_err(bgmac, "Unsupported speed: %d\n", bgmac->mac_speed); } if (bgmac->mac_duplex == DUPLEX_HALF) set |= BGMAC_CMDCFG_HD; bgmac_cmdcfg_maskset(bgmac, mask, set, true); }
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_enable */ static void bgmac_enable(struct bgmac *bgmac) { u32 cmdcfg_sr; u32 cmdcfg; u32 mode; if (bgmac->feature_flags & BGMAC_FEAT_CMDCFG_SR_REV4) cmdcfg_sr = BGMAC_CMDCFG_SR_REV4; else cmdcfg_sr = BGMAC_CMDCFG_SR_REV0; cmdcfg = bgmac_read(bgmac, BGMAC_CMDCFG); bgmac_cmdcfg_maskset(bgmac, ~(BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE), cmdcfg_sr, true); udelay(2); cmdcfg |= BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE; bgmac_write(bgmac, BGMAC_CMDCFG, cmdcfg); mode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >> BGMAC_DS_MM_SHIFT; if (bgmac->feature_flags & BGMAC_FEAT_CLKCTLST || mode != 0) bgmac_set(bgmac, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT); if (!(bgmac->feature_flags & BGMAC_FEAT_CLKCTLST) && mode == 2) bgmac_cco_ctl_maskset(bgmac, 1, ~0, BGMAC_CHIPCTL_1_RXC_DLL_BYPASS); if (bgmac->feature_flags & (BGMAC_FEAT_FLW_CTRL1 | BGMAC_FEAT_FLW_CTRL2)) { u32 fl_ctl; if (bgmac->feature_flags & BGMAC_FEAT_FLW_CTRL1) fl_ctl = 0x2300e1; else fl_ctl = 0x03cb04cb; bgmac_write(bgmac, BGMAC_FLOW_CTL_THRESH, fl_ctl); bgmac_write(bgmac, BGMAC_PAUSE_CTL, 0x27fff); } if (bgmac->feature_flags & BGMAC_FEAT_SET_RXQ_CLK) { u32 rxq_ctl; u16 bp_clk; u8 mdp; rxq_ctl = bgmac_read(bgmac, BGMAC_RXQ_CTL); rxq_ctl &= ~BGMAC_RXQ_CTL_MDP_MASK; bp_clk = bgmac_get_bus_clock(bgmac) / 1000000; mdp = (bp_clk * 128 / 1000) - 3; rxq_ctl |= (mdp << BGMAC_RXQ_CTL_MDP_SHIFT); bgmac_write(bgmac, BGMAC_RXQ_CTL, rxq_ctl); } }
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_enable */ static void bgmac_enable(struct bgmac *bgmac) { struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo; u32 cmdcfg; u32 mode; u32 rxq_ctl; u32 fl_ctl; u16 bp_clk; u8 mdp; cmdcfg = bgmac_read(bgmac, BGMAC_CMDCFG); bgmac_cmdcfg_maskset(bgmac, ~(BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE), BGMAC_CMDCFG_SR(bgmac->core->id.rev), true); udelay(2); cmdcfg |= BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE; bgmac_write(bgmac, BGMAC_CMDCFG, cmdcfg); mode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >> BGMAC_DS_MM_SHIFT; if (ci->id != BCMA_CHIP_ID_BCM47162 || mode != 0) bgmac_set(bgmac, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT); if (ci->id == BCMA_CHIP_ID_BCM47162 && mode == 2) bcma_chipco_chipctl_maskset(&bgmac->core->bus->drv_cc, 1, ~0, BGMAC_CHIPCTL_1_RXC_DLL_BYPASS); switch (ci->id) { case BCMA_CHIP_ID_BCM5357: case BCMA_CHIP_ID_BCM4749: case BCMA_CHIP_ID_BCM53572: case BCMA_CHIP_ID_BCM4716: case BCMA_CHIP_ID_BCM47162: fl_ctl = 0x03cb04cb; if (ci->id == BCMA_CHIP_ID_BCM5357 || ci->id == BCMA_CHIP_ID_BCM4749 || ci->id == BCMA_CHIP_ID_BCM53572) fl_ctl = 0x2300e1; bgmac_write(bgmac, BGMAC_FLOW_CTL_THRESH, fl_ctl); bgmac_write(bgmac, BGMAC_PAUSE_CTL, 0x27fff); break; } if (ci->id != BCMA_CHIP_ID_BCM4707 && ci->id != BCMA_CHIP_ID_BCM53018) { rxq_ctl = bgmac_read(bgmac, BGMAC_RXQ_CTL); rxq_ctl &= ~BGMAC_RXQ_CTL_MDP_MASK; bp_clk = bcma_pmu_get_bus_clock(&bgmac->core->bus->drv_cc) / 1000000; mdp = (bp_clk * 128 / 1000) - 3; rxq_ctl |= (mdp << BGMAC_RXQ_CTL_MDP_SHIFT); bgmac_write(bgmac, BGMAC_RXQ_CTL, rxq_ctl); } }
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_speed */ static void bgmac_speed(struct bgmac *bgmac, int speed) { u32 mask = ~(BGMAC_CMDCFG_ES_MASK | BGMAC_CMDCFG_HD); u32 set = 0; if (speed & BGMAC_SPEED_10) set |= BGMAC_CMDCFG_ES_10; if (speed & BGMAC_SPEED_100) set |= BGMAC_CMDCFG_ES_100; if (speed & BGMAC_SPEED_1000) set |= BGMAC_CMDCFG_ES_1000; if (!bgmac->full_duplex) set |= BGMAC_CMDCFG_HD; bgmac_cmdcfg_maskset(bgmac, mask, set, true); }
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipreset */ static void bgmac_chip_reset(struct bgmac *bgmac) { struct bcma_device *core = bgmac->core; struct bcma_bus *bus = core->bus; struct bcma_chipinfo *ci = &bus->chipinfo; u32 flags; u32 iost; int i; if (bcma_core_is_enabled(core)) { if (!bgmac->stats_grabbed) { /* bgmac_chip_stats_update(bgmac); */ bgmac->stats_grabbed = true; } for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) bgmac_dma_tx_reset(bgmac, &bgmac->tx_ring[i]); bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_ML, false); udelay(1); for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) bgmac_dma_rx_reset(bgmac, &bgmac->rx_ring[i]); /* TODO: Clear software multicast filter list */ } iost = bcma_aread32(core, BCMA_IOST); if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM47186) || (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg == 10) || (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188)) iost &= ~BGMAC_BCMA_IOST_ATTACHED; /* 3GMAC: for BCM4707 & BCM47094, only do core reset at bgmac_probe() */ if (ci->id != BCMA_CHIP_ID_BCM4707 && ci->id != BCMA_CHIP_ID_BCM47094) { flags = 0; if (iost & BGMAC_BCMA_IOST_ATTACHED) { flags = BGMAC_BCMA_IOCTL_SW_CLKEN; if (!bgmac->has_robosw) flags |= BGMAC_BCMA_IOCTL_SW_RESET; } bcma_core_enable(core, flags); } /* Request Misc PLL for corerev > 2 */ if (core->id.rev > 2 && !bgmac_is_bcm4707_family(bgmac)) { bgmac_set(bgmac, BCMA_CLKCTLST, BGMAC_BCMA_CLKCTLST_MISC_PLL_REQ); bgmac_wait_value(bgmac->core, BCMA_CLKCTLST, BGMAC_BCMA_CLKCTLST_MISC_PLL_ST, BGMAC_BCMA_CLKCTLST_MISC_PLL_ST, 1000); } if (ci->id == BCMA_CHIP_ID_BCM5357 || ci->id == BCMA_CHIP_ID_BCM4749 || ci->id == BCMA_CHIP_ID_BCM53572) { struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc; u8 et_swtype = 0; u8 sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHY | BGMAC_CHIPCTL_1_IF_TYPE_MII; char buf[4]; if (bcm47xx_nvram_getenv("et_swtype", buf, sizeof(buf)) > 0) { if (kstrtou8(buf, 0, &et_swtype)) bgmac_err(bgmac, "Failed to parse et_swtype (%s)\n", buf); et_swtype &= 0x0f; et_swtype <<= 4; sw_type = et_swtype; } else if (ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM5358) { sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII; } else if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg == BCMA_PKG_ID_BCM47186) || (ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg == 10) || (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188)) { sw_type = BGMAC_CHIPCTL_1_IF_TYPE_RGMII | BGMAC_CHIPCTL_1_SW_TYPE_RGMII; } bcma_chipco_chipctl_maskset(cc, 1, ~(BGMAC_CHIPCTL_1_IF_TYPE_MASK | BGMAC_CHIPCTL_1_SW_TYPE_MASK), sw_type); } if (iost & BGMAC_BCMA_IOST_ATTACHED && !bgmac->has_robosw) bcma_awrite32(core, BCMA_IOCTL, bcma_aread32(core, BCMA_IOCTL) & ~BGMAC_BCMA_IOCTL_SW_RESET); /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_reset * Specs don't say about using BGMAC_CMDCFG_SR, but in this routine * BGMAC_CMDCFG is read _after_ putting chip in a reset. So it has to * be keps until taking MAC out of the reset. */ bgmac_cmdcfg_maskset(bgmac, ~(BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE | BGMAC_CMDCFG_RPI | BGMAC_CMDCFG_TAI | BGMAC_CMDCFG_HD | BGMAC_CMDCFG_ML | BGMAC_CMDCFG_CFE | BGMAC_CMDCFG_RL | BGMAC_CMDCFG_RED | BGMAC_CMDCFG_PE | BGMAC_CMDCFG_TPI | BGMAC_CMDCFG_PAD_EN | BGMAC_CMDCFG_PF), BGMAC_CMDCFG_PROM | BGMAC_CMDCFG_NLC | BGMAC_CMDCFG_CFE | BGMAC_CMDCFG_SR(core->id.rev), false); bgmac->mac_speed = SPEED_UNKNOWN; bgmac->mac_duplex = DUPLEX_UNKNOWN; bgmac_clear_mib(bgmac); if (core->id.id == BCMA_CORE_4706_MAC_GBIT) bcma_maskset32(bgmac->cmn, BCMA_GMAC_CMN_PHY_CTL, ~0, BCMA_GMAC_CMN_PC_MTE); else bgmac_set(bgmac, BGMAC_PHY_CNTL, BGMAC_PC_MTE); bgmac_miiconfig(bgmac); bgmac_phy_init(bgmac); netdev_reset_queue(bgmac->net_dev); }
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipreset */ static void bgmac_chip_reset(struct bgmac *bgmac) { u32 cmdcfg_sr; int i; if (bgmac_clk_enabled(bgmac)) { if (!bgmac->stats_grabbed) { /* bgmac_chip_stats_update(bgmac); */ bgmac->stats_grabbed = true; } for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) bgmac_dma_tx_reset(bgmac, &bgmac->tx_ring[i]); bgmac_cmdcfg_maskset(bgmac, ~0, BGMAC_CMDCFG_ML, false); udelay(1); for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) bgmac_dma_rx_reset(bgmac, &bgmac->rx_ring[i]); /* TODO: Clear software multicast filter list */ } if (!(bgmac->feature_flags & BGMAC_FEAT_IDM_MASK)) bgmac_chip_reset_idm_config(bgmac); /* Request Misc PLL for corerev > 2 */ if (bgmac->feature_flags & BGMAC_FEAT_MISC_PLL_REQ) { bgmac_set(bgmac, BCMA_CLKCTLST, BGMAC_BCMA_CLKCTLST_MISC_PLL_REQ); bgmac_wait_value(bgmac, BCMA_CLKCTLST, BGMAC_BCMA_CLKCTLST_MISC_PLL_ST, BGMAC_BCMA_CLKCTLST_MISC_PLL_ST, 1000); } if (bgmac->feature_flags & BGMAC_FEAT_SW_TYPE_PHY) { u8 et_swtype = 0; u8 sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHY | BGMAC_CHIPCTL_1_IF_TYPE_MII; char buf[4]; if (bcm47xx_nvram_getenv("et_swtype", buf, sizeof(buf)) > 0) { if (kstrtou8(buf, 0, &et_swtype)) dev_err(bgmac->dev, "Failed to parse et_swtype (%s)\n", buf); et_swtype &= 0x0f; et_swtype <<= 4; sw_type = et_swtype; } else if (bgmac->feature_flags & BGMAC_FEAT_SW_TYPE_EPHYRMII) { sw_type = BGMAC_CHIPCTL_1_IF_TYPE_RMII | BGMAC_CHIPCTL_1_SW_TYPE_EPHYRMII; } else if (bgmac->feature_flags & BGMAC_FEAT_SW_TYPE_RGMII) { sw_type = BGMAC_CHIPCTL_1_IF_TYPE_RGMII | BGMAC_CHIPCTL_1_SW_TYPE_RGMII; } bgmac_cco_ctl_maskset(bgmac, 1, ~(BGMAC_CHIPCTL_1_IF_TYPE_MASK | BGMAC_CHIPCTL_1_SW_TYPE_MASK), sw_type); } else if (bgmac->feature_flags & BGMAC_FEAT_CC4_IF_SW_TYPE) { u32 sw_type = BGMAC_CHIPCTL_4_IF_TYPE_MII | BGMAC_CHIPCTL_4_SW_TYPE_EPHY; u8 et_swtype = 0; char buf[4]; if (bcm47xx_nvram_getenv("et_swtype", buf, sizeof(buf)) > 0) { if (kstrtou8(buf, 0, &et_swtype)) dev_err(bgmac->dev, "Failed to parse et_swtype (%s)\n", buf); sw_type = (et_swtype & 0x0f) << 12; } else if (bgmac->feature_flags & BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII) { sw_type = BGMAC_CHIPCTL_4_IF_TYPE_RGMII | BGMAC_CHIPCTL_4_SW_TYPE_RGMII; } bgmac_cco_ctl_maskset(bgmac, 4, ~(BGMAC_CHIPCTL_4_IF_TYPE_MASK | BGMAC_CHIPCTL_4_SW_TYPE_MASK), sw_type); } else if (bgmac->feature_flags & BGMAC_FEAT_CC7_IF_TYPE_RGMII) { bgmac_cco_ctl_maskset(bgmac, 7, ~BGMAC_CHIPCTL_7_IF_TYPE_MASK, BGMAC_CHIPCTL_7_IF_TYPE_RGMII); } /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/gmac_reset * Specs don't say about using BGMAC_CMDCFG_SR, but in this routine * BGMAC_CMDCFG is read _after_ putting chip in a reset. So it has to * be keps until taking MAC out of the reset. */ if (bgmac->feature_flags & BGMAC_FEAT_CMDCFG_SR_REV4) cmdcfg_sr = BGMAC_CMDCFG_SR_REV4; else cmdcfg_sr = BGMAC_CMDCFG_SR_REV0; bgmac_cmdcfg_maskset(bgmac, ~(BGMAC_CMDCFG_TE | BGMAC_CMDCFG_RE | BGMAC_CMDCFG_RPI | BGMAC_CMDCFG_TAI | BGMAC_CMDCFG_HD | BGMAC_CMDCFG_ML | BGMAC_CMDCFG_CFE | BGMAC_CMDCFG_RL | BGMAC_CMDCFG_RED | BGMAC_CMDCFG_PE | BGMAC_CMDCFG_TPI | BGMAC_CMDCFG_PAD_EN | BGMAC_CMDCFG_PF), BGMAC_CMDCFG_PROM | BGMAC_CMDCFG_NLC | BGMAC_CMDCFG_CFE | cmdcfg_sr, false); bgmac->mac_speed = SPEED_UNKNOWN; bgmac->mac_duplex = DUPLEX_UNKNOWN; bgmac_clear_mib(bgmac); if (bgmac->feature_flags & BGMAC_FEAT_CMN_PHY_CTL) bgmac_cmn_maskset32(bgmac, BCMA_GMAC_CMN_PHY_CTL, ~0, BCMA_GMAC_CMN_PC_MTE); else bgmac_set(bgmac, BGMAC_PHY_CNTL, BGMAC_PC_MTE); bgmac_miiconfig(bgmac); if (bgmac->mii_bus) bgmac->mii_bus->reset(bgmac->mii_bus); netdev_reset_queue(bgmac->net_dev); }