static void bgmac_chip_reset_idm_config(struct bgmac *bgmac) { u32 iost; iost = bgmac_idm_read(bgmac, BCMA_IOST); if (bgmac->feature_flags & BGMAC_FEAT_IOST_ATTACHED) iost &= ~BGMAC_BCMA_IOST_ATTACHED; /* 3GMAC: for BCM4707 & BCM47094, only do core reset at bgmac_probe() */ if (!(bgmac->feature_flags & BGMAC_FEAT_NO_RESET)) { u32 flags = 0; if (iost & BGMAC_BCMA_IOST_ATTACHED) { flags = BGMAC_BCMA_IOCTL_SW_CLKEN; if (!bgmac->has_robosw) flags |= BGMAC_BCMA_IOCTL_SW_RESET; } bgmac_clk_enable(bgmac, flags); } if (iost & BGMAC_BCMA_IOST_ATTACHED && !bgmac->has_robosw) bgmac_idm_write(bgmac, BCMA_IOCTL, bgmac_idm_read(bgmac, BCMA_IOCTL) & ~BGMAC_BCMA_IOCTL_SW_RESET); }
static bool platform_bgmac_clk_enabled(struct bgmac *bgmac) { if ((bgmac_idm_read(bgmac, BCMA_IOCTL) & (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC)) != BCMA_IOCTL_CLK) return false; if (bgmac_idm_read(bgmac, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET) return false; return true; }
static void platform_bgmac_clk_enable(struct bgmac *bgmac, u32 flags) { bgmac_idm_write(bgmac, BCMA_IOCTL, (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC | flags)); bgmac_idm_read(bgmac, BCMA_IOCTL); bgmac_idm_write(bgmac, BCMA_RESET_CTL, 0); bgmac_idm_read(bgmac, BCMA_RESET_CTL); udelay(1); bgmac_idm_write(bgmac, BCMA_IOCTL, (BCMA_IOCTL_CLK | flags)); bgmac_idm_read(bgmac, BCMA_IOCTL); udelay(1); }
static void bgmac_miiconfig(struct bgmac *bgmac) { if (bgmac->feature_flags & BGMAC_FEAT_FORCE_SPEED_2500) { bgmac_idm_write(bgmac, BCMA_IOCTL, bgmac_idm_read(bgmac, BCMA_IOCTL) | 0x40 | BGMAC_BCMA_IOCTL_SW_CLKEN); bgmac->mac_speed = SPEED_2500; bgmac->mac_duplex = DUPLEX_FULL; bgmac_mac_speed(bgmac); } else { u8 imode; imode = (bgmac_read(bgmac, BGMAC_DEV_STATUS) & BGMAC_DS_MM_MASK) >> BGMAC_DS_MM_SHIFT; if (imode == 0 || imode == 1) { bgmac->mac_speed = SPEED_100; bgmac->mac_duplex = DUPLEX_FULL; bgmac_mac_speed(bgmac); } } }
static int bgmac_dma_alloc(struct bgmac *bgmac) { struct device *dma_dev = bgmac->dma_dev; struct bgmac_dma_ring *ring; static const u16 ring_base[] = { BGMAC_DMA_BASE0, BGMAC_DMA_BASE1, BGMAC_DMA_BASE2, BGMAC_DMA_BASE3, }; int size; /* ring size: different for Tx and Rx */ int err; int i; BUILD_BUG_ON(BGMAC_MAX_TX_RINGS > ARRAY_SIZE(ring_base)); BUILD_BUG_ON(BGMAC_MAX_RX_RINGS > ARRAY_SIZE(ring_base)); if (!(bgmac->feature_flags & BGMAC_FEAT_IDM_MASK)) { if (!(bgmac_idm_read(bgmac, BCMA_IOST) & BCMA_IOST_DMA64)) { dev_err(bgmac->dev, "Core does not report 64-bit DMA\n"); return -ENOTSUPP; } } for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) { ring = &bgmac->tx_ring[i]; ring->mmio_base = ring_base[i]; /* Alloc ring of descriptors */ size = BGMAC_TX_RING_SLOTS * sizeof(struct bgmac_dma_desc); ring->cpu_base = dma_zalloc_coherent(dma_dev, size, &ring->dma_base, GFP_KERNEL); if (!ring->cpu_base) { dev_err(bgmac->dev, "Allocation of TX ring 0x%X failed\n", ring->mmio_base); goto err_dma_free; } ring->unaligned = bgmac_dma_unaligned(bgmac, ring, BGMAC_DMA_RING_TX); if (ring->unaligned) ring->index_base = lower_32_bits(ring->dma_base); else ring->index_base = 0; /* No need to alloc TX slots yet */ } for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) { ring = &bgmac->rx_ring[i]; ring->mmio_base = ring_base[i]; /* Alloc ring of descriptors */ size = BGMAC_RX_RING_SLOTS * sizeof(struct bgmac_dma_desc); ring->cpu_base = dma_zalloc_coherent(dma_dev, size, &ring->dma_base, GFP_KERNEL); if (!ring->cpu_base) { dev_err(bgmac->dev, "Allocation of RX ring 0x%X failed\n", ring->mmio_base); err = -ENOMEM; goto err_dma_free; } ring->unaligned = bgmac_dma_unaligned(bgmac, ring, BGMAC_DMA_RING_RX); if (ring->unaligned) ring->index_base = lower_32_bits(ring->dma_base); else ring->index_base = 0; } return 0; err_dma_free: bgmac_dma_free(bgmac); return -ENOMEM; }
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipreset */ static void bgmac_chip_reset(struct bgmac *bgmac) { u32 cmdcfg_sr; u32 iost; 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 */ } iost = bgmac_idm_read(bgmac, BCMA_IOST); if (bgmac->feature_flags & BGMAC_FEAT_IOST_ATTACHED) iost &= ~BGMAC_BCMA_IOST_ATTACHED; /* 3GMAC: for BCM4707 & BCM47094, only do core reset at bgmac_probe() */ if (!(bgmac->feature_flags & BGMAC_FEAT_NO_RESET)) { u32 flags = 0; if (iost & BGMAC_BCMA_IOST_ATTACHED) { flags = BGMAC_BCMA_IOCTL_SW_CLKEN; if (!bgmac->has_robosw) flags |= BGMAC_BCMA_IOCTL_SW_RESET; } bgmac_clk_enable(bgmac, flags); } /* 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); } if (iost & BGMAC_BCMA_IOST_ATTACHED && !bgmac->has_robosw) bgmac_idm_write(bgmac, BCMA_IOCTL, bgmac_idm_read(bgmac, 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. */ 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); }